Module Name:    xsrc
Committed By:   jmcneill
Date:           Sat Oct 22 22:05:27 UTC 2011

Added Files:
        xsrc/local/programs/xsetwallpaper: xsetwallpaper.c

Log Message:
xsetwallpaper is a utility to load images into the X11 root window.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 xsrc/local/programs/xsetwallpaper/xsetwallpaper.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: xsrc/local/programs/xsetwallpaper/xsetwallpaper.c
diff -u /dev/null xsrc/local/programs/xsetwallpaper/xsetwallpaper.c:1.1
--- /dev/null	Sat Oct 22 22:05:27 2011
+++ xsrc/local/programs/xsetwallpaper/xsetwallpaper.c	Sat Oct 22 22:05:27 2011
@@ -0,0 +1,188 @@
+/* $NetBSD: xsetwallpaper.c,v 1.1 2011/10/22 22:05:27 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: xsetwallpaper.c,v 1.1 2011/10/22 22:05:27 jmcneill Exp $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+
+#include "stbi.h"
+
+#define DEFAULT_FILL_COLOR	"#000000"
+
+static void
+usage(const char *pn)
+{
+	fprintf(stderr, "usage: %s [-f fillcolor] filename\n", pn);
+	exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+	const char *fill_color = DEFAULT_FILL_COLOR;
+	const char *pn = argv[0];
+	uint8_t *data;
+	unsigned int root_width, root_height, root_border_width, root_depth;
+	int root_x, root_y;
+	int bitmap_pad, srcx, srcy, dstx, dsty;
+	int imagew, imageh, imagebpp;
+	int ch, i;
+	int screen, default_depth;
+	Display *display;
+	Colormap colormap;
+	XImage *image;
+	Pixmap pixmap;
+	XColor color;
+	Window window;
+	GC gc;
+
+	while ((ch = getopt(argc, argv, "f:h")) != -1) {
+		switch (ch) {
+		case 'f':
+			fill_color = optarg;
+			break;
+		case 'h':
+		default:
+			usage(pn);
+			/* NOTREACHED */
+		}
+	}
+	argc -= optind;
+	argv += optind;
+			
+	if (argc != 1)
+		usage(pn);
+
+	/* Load the image */
+	data = stbi_load(argv[0], &imagew, &imageh, &imagebpp, 4);
+	if (data == NULL)
+		errx(EXIT_FAILURE, "failed to load %s", argv[0]);
+
+	/* swap red and blue */
+	for (i = 0; i < imagew * imageh * 4; i += 4) {
+		uint8_t p;
+		p = data[i + 0];
+		data[i + 0] = data[i + 2];
+		data[i + 2] = p;
+	}
+
+#ifdef DEBUG
+	printf("%s: %dx%d %dbpp\n", argv[0], imagew, imageh, imagebpp * 8);
+#endif
+
+	/* open the display */
+	display = XOpenDisplay(NULL);
+	if (display == NULL) {
+		errx(EXIT_FAILURE, "couldn't open display: %s",
+		    getenv("DISPLAY"));
+	}
+	screen = DefaultScreen(display);
+	default_depth = DefaultDepth(display, screen);
+	colormap = DefaultColormap(display, 0);
+
+	/* get root window geometry */
+	if (!XGetGeometry(display, XDefaultRootWindow(display), &window,
+	    &root_x, &root_y, &root_width, &root_height,
+	    &root_border_width, &root_depth)) {
+		errx(EXIT_FAILURE, "couldn't get screen dimensions\n");
+	}
+
+#ifdef DEBUG
+	printf("screen is %dx%d\n", root_width, root_height);
+#endif
+
+	XSync(display, False);
+
+	/* Parse the fill colour and allocate it */
+	if (!XParseColor(display, colormap, fill_color, &color)) {
+		errx(EXIT_FAILURE, "couldn't parse color '%s'", fill_color);
+	}
+	if (!XAllocColor(display, colormap, &color)) {
+		errx(EXIT_FAILURE, "XAllocColor failed");
+	}
+
+	/* Create an XImage from our raw image data */
+	if (default_depth >= 24)
+		bitmap_pad = 32;
+	else if (default_depth >= 16)
+		bitmap_pad = 16;
+	else
+		bitmap_pad = 8;
+	image = XCreateImage(display, CopyFromParent, imagebpp * 8,
+	    ZPixmap, 0, (char *)data, imagew, imageh, bitmap_pad, 0);
+	if (image == NULL) {
+		errx(EXIT_FAILURE, "XCreateImage failed");
+	}
+	XInitImage(image);
+	image->byte_order = LSBFirst;	/* ??? */
+
+	/* Create a graphics context for our new pixmap */
+	gc = XCreateGC(display, window, 0, NULL);
+
+	/* Create a pixmap the size of the root window */
+	pixmap = XCreatePixmap(display, window,
+	    root_width, root_height, root_depth);
+
+	/* Fill the background with the specified fill colour */
+	XSetForeground(display, gc, color.pixel);
+	XFillRectangle(display, pixmap, gc, 0, 0, root_width, root_height); 
+
+	/* Copy the image to the pixmal, centering it on screen */
+	if ((unsigned int)imagew > root_width) {
+		srcx = (imagew - root_width) / 2;
+		dstx = 0;
+	} else {
+		srcx = 0;
+		dstx = (root_width - imagew) / 2;
+	}
+	if ((unsigned int)imageh > root_height) {
+		srcy = (imageh - root_height) / 2;
+		dsty = 0;
+	} else {
+		srcy = 0;
+		dsty = (root_height - imageh) / 2;
+	}
+	XPutImage(display, pixmap, gc, image,
+	    srcx, srcy, dstx, dsty,
+	    root_width, root_height);
+
+	/* Set the background pixmap for the window */
+	XSetWindowBackgroundPixmap(display, window, pixmap);
+	XClearWindow(display, window);
+
+	/* Cleanup */
+	XFreePixmap(display, pixmap);
+	XCloseDisplay(display);
+
+	return EXIT_SUCCESS;
+}

Reply via email to