xsetwallpaper.c revision e6987d98
1e6987d98Sjmcneill/* $NetBSD: xsetwallpaper.c,v 1.1 2011/10/22 22:05:27 jmcneill Exp $ */ 2e6987d98Sjmcneill 3e6987d98Sjmcneill/*- 4e6987d98Sjmcneill * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca> 5e6987d98Sjmcneill * All rights reserved. 6e6987d98Sjmcneill * 7e6987d98Sjmcneill * Redistribution and use in source and binary forms, with or without 8e6987d98Sjmcneill * modification, are permitted provided that the following conditions 9e6987d98Sjmcneill * are met: 10e6987d98Sjmcneill * 1. Redistributions of source code must retain the above copyright 11e6987d98Sjmcneill * notice, this list of conditions and the following disclaimer. 12e6987d98Sjmcneill * 2. The name of the author may not be used to endorse or promote products 13e6987d98Sjmcneill * derived from this software without specific prior written permission. 14e6987d98Sjmcneill * 15e6987d98Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16e6987d98Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17e6987d98Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18e6987d98Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19e6987d98Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20e6987d98Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21e6987d98Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22e6987d98Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23e6987d98Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e6987d98Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e6987d98Sjmcneill * SUCH DAMAGE. 26e6987d98Sjmcneill */ 27e6987d98Sjmcneill 28e6987d98Sjmcneill#include <sys/cdefs.h> 29e6987d98Sjmcneill__RCSID("$NetBSD: xsetwallpaper.c,v 1.1 2011/10/22 22:05:27 jmcneill Exp $"); 30e6987d98Sjmcneill 31e6987d98Sjmcneill#include <err.h> 32e6987d98Sjmcneill#include <stdio.h> 33e6987d98Sjmcneill#include <stdlib.h> 34e6987d98Sjmcneill#include <unistd.h> 35e6987d98Sjmcneill 36e6987d98Sjmcneill#include <X11/Xlib.h> 37e6987d98Sjmcneill 38e6987d98Sjmcneill#include "stbi.h" 39e6987d98Sjmcneill 40e6987d98Sjmcneill#define DEFAULT_FILL_COLOR "#000000" 41e6987d98Sjmcneill 42e6987d98Sjmcneillstatic void 43e6987d98Sjmcneillusage(const char *pn) 44e6987d98Sjmcneill{ 45e6987d98Sjmcneill fprintf(stderr, "usage: %s [-f fillcolor] filename\n", pn); 46e6987d98Sjmcneill exit(EXIT_FAILURE); 47e6987d98Sjmcneill} 48e6987d98Sjmcneill 49e6987d98Sjmcneillint 50e6987d98Sjmcneillmain(int argc, char *argv[]) 51e6987d98Sjmcneill{ 52e6987d98Sjmcneill const char *fill_color = DEFAULT_FILL_COLOR; 53e6987d98Sjmcneill const char *pn = argv[0]; 54e6987d98Sjmcneill uint8_t *data; 55e6987d98Sjmcneill unsigned int root_width, root_height, root_border_width, root_depth; 56e6987d98Sjmcneill int root_x, root_y; 57e6987d98Sjmcneill int bitmap_pad, srcx, srcy, dstx, dsty; 58e6987d98Sjmcneill int imagew, imageh, imagebpp; 59e6987d98Sjmcneill int ch, i; 60e6987d98Sjmcneill int screen, default_depth; 61e6987d98Sjmcneill Display *display; 62e6987d98Sjmcneill Colormap colormap; 63e6987d98Sjmcneill XImage *image; 64e6987d98Sjmcneill Pixmap pixmap; 65e6987d98Sjmcneill XColor color; 66e6987d98Sjmcneill Window window; 67e6987d98Sjmcneill GC gc; 68e6987d98Sjmcneill 69e6987d98Sjmcneill while ((ch = getopt(argc, argv, "f:h")) != -1) { 70e6987d98Sjmcneill switch (ch) { 71e6987d98Sjmcneill case 'f': 72e6987d98Sjmcneill fill_color = optarg; 73e6987d98Sjmcneill break; 74e6987d98Sjmcneill case 'h': 75e6987d98Sjmcneill default: 76e6987d98Sjmcneill usage(pn); 77e6987d98Sjmcneill /* NOTREACHED */ 78e6987d98Sjmcneill } 79e6987d98Sjmcneill } 80e6987d98Sjmcneill argc -= optind; 81e6987d98Sjmcneill argv += optind; 82e6987d98Sjmcneill 83e6987d98Sjmcneill if (argc != 1) 84e6987d98Sjmcneill usage(pn); 85e6987d98Sjmcneill 86e6987d98Sjmcneill /* Load the image */ 87e6987d98Sjmcneill data = stbi_load(argv[0], &imagew, &imageh, &imagebpp, 4); 88e6987d98Sjmcneill if (data == NULL) 89e6987d98Sjmcneill errx(EXIT_FAILURE, "failed to load %s", argv[0]); 90e6987d98Sjmcneill 91e6987d98Sjmcneill /* swap red and blue */ 92e6987d98Sjmcneill for (i = 0; i < imagew * imageh * 4; i += 4) { 93e6987d98Sjmcneill uint8_t p; 94e6987d98Sjmcneill p = data[i + 0]; 95e6987d98Sjmcneill data[i + 0] = data[i + 2]; 96e6987d98Sjmcneill data[i + 2] = p; 97e6987d98Sjmcneill } 98e6987d98Sjmcneill 99e6987d98Sjmcneill#ifdef DEBUG 100e6987d98Sjmcneill printf("%s: %dx%d %dbpp\n", argv[0], imagew, imageh, imagebpp * 8); 101e6987d98Sjmcneill#endif 102e6987d98Sjmcneill 103e6987d98Sjmcneill /* open the display */ 104e6987d98Sjmcneill display = XOpenDisplay(NULL); 105e6987d98Sjmcneill if (display == NULL) { 106e6987d98Sjmcneill errx(EXIT_FAILURE, "couldn't open display: %s", 107e6987d98Sjmcneill getenv("DISPLAY")); 108e6987d98Sjmcneill } 109e6987d98Sjmcneill screen = DefaultScreen(display); 110e6987d98Sjmcneill default_depth = DefaultDepth(display, screen); 111e6987d98Sjmcneill colormap = DefaultColormap(display, 0); 112e6987d98Sjmcneill 113e6987d98Sjmcneill /* get root window geometry */ 114e6987d98Sjmcneill if (!XGetGeometry(display, XDefaultRootWindow(display), &window, 115e6987d98Sjmcneill &root_x, &root_y, &root_width, &root_height, 116e6987d98Sjmcneill &root_border_width, &root_depth)) { 117e6987d98Sjmcneill errx(EXIT_FAILURE, "couldn't get screen dimensions\n"); 118e6987d98Sjmcneill } 119e6987d98Sjmcneill 120e6987d98Sjmcneill#ifdef DEBUG 121e6987d98Sjmcneill printf("screen is %dx%d\n", root_width, root_height); 122e6987d98Sjmcneill#endif 123e6987d98Sjmcneill 124e6987d98Sjmcneill XSync(display, False); 125e6987d98Sjmcneill 126e6987d98Sjmcneill /* Parse the fill colour and allocate it */ 127e6987d98Sjmcneill if (!XParseColor(display, colormap, fill_color, &color)) { 128e6987d98Sjmcneill errx(EXIT_FAILURE, "couldn't parse color '%s'", fill_color); 129e6987d98Sjmcneill } 130e6987d98Sjmcneill if (!XAllocColor(display, colormap, &color)) { 131e6987d98Sjmcneill errx(EXIT_FAILURE, "XAllocColor failed"); 132e6987d98Sjmcneill } 133e6987d98Sjmcneill 134e6987d98Sjmcneill /* Create an XImage from our raw image data */ 135e6987d98Sjmcneill if (default_depth >= 24) 136e6987d98Sjmcneill bitmap_pad = 32; 137e6987d98Sjmcneill else if (default_depth >= 16) 138e6987d98Sjmcneill bitmap_pad = 16; 139e6987d98Sjmcneill else 140e6987d98Sjmcneill bitmap_pad = 8; 141e6987d98Sjmcneill image = XCreateImage(display, CopyFromParent, imagebpp * 8, 142e6987d98Sjmcneill ZPixmap, 0, (char *)data, imagew, imageh, bitmap_pad, 0); 143e6987d98Sjmcneill if (image == NULL) { 144e6987d98Sjmcneill errx(EXIT_FAILURE, "XCreateImage failed"); 145e6987d98Sjmcneill } 146e6987d98Sjmcneill XInitImage(image); 147e6987d98Sjmcneill image->byte_order = LSBFirst; /* ??? */ 148e6987d98Sjmcneill 149e6987d98Sjmcneill /* Create a graphics context for our new pixmap */ 150e6987d98Sjmcneill gc = XCreateGC(display, window, 0, NULL); 151e6987d98Sjmcneill 152e6987d98Sjmcneill /* Create a pixmap the size of the root window */ 153e6987d98Sjmcneill pixmap = XCreatePixmap(display, window, 154e6987d98Sjmcneill root_width, root_height, root_depth); 155e6987d98Sjmcneill 156e6987d98Sjmcneill /* Fill the background with the specified fill colour */ 157e6987d98Sjmcneill XSetForeground(display, gc, color.pixel); 158e6987d98Sjmcneill XFillRectangle(display, pixmap, gc, 0, 0, root_width, root_height); 159e6987d98Sjmcneill 160e6987d98Sjmcneill /* Copy the image to the pixmal, centering it on screen */ 161e6987d98Sjmcneill if ((unsigned int)imagew > root_width) { 162e6987d98Sjmcneill srcx = (imagew - root_width) / 2; 163e6987d98Sjmcneill dstx = 0; 164e6987d98Sjmcneill } else { 165e6987d98Sjmcneill srcx = 0; 166e6987d98Sjmcneill dstx = (root_width - imagew) / 2; 167e6987d98Sjmcneill } 168e6987d98Sjmcneill if ((unsigned int)imageh > root_height) { 169e6987d98Sjmcneill srcy = (imageh - root_height) / 2; 170e6987d98Sjmcneill dsty = 0; 171e6987d98Sjmcneill } else { 172e6987d98Sjmcneill srcy = 0; 173e6987d98Sjmcneill dsty = (root_height - imageh) / 2; 174e6987d98Sjmcneill } 175e6987d98Sjmcneill XPutImage(display, pixmap, gc, image, 176e6987d98Sjmcneill srcx, srcy, dstx, dsty, 177e6987d98Sjmcneill root_width, root_height); 178e6987d98Sjmcneill 179e6987d98Sjmcneill /* Set the background pixmap for the window */ 180e6987d98Sjmcneill XSetWindowBackgroundPixmap(display, window, pixmap); 181e6987d98Sjmcneill XClearWindow(display, window); 182e6987d98Sjmcneill 183e6987d98Sjmcneill /* Cleanup */ 184e6987d98Sjmcneill XFreePixmap(display, pixmap); 185e6987d98Sjmcneill XCloseDisplay(display); 186e6987d98Sjmcneill 187e6987d98Sjmcneill return EXIT_SUCCESS; 188e6987d98Sjmcneill} 189