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