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