tech-x11 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

xsetwallpaper: bugfix + enhancements



This's been lying around in my tree for some time. The patch
contains:

- fix for segfault with `-s' and a small image.
- additional display modes: fit-to-screen, tile.
- XPM support.
- man page.

-RVP
diff -urN a/src/distrib/sets/lists/xbase/mi b/src/distrib/sets/lists/xbase/mi
--- a/src/distrib/sets/lists/xbase/mi	2021-04-27 06:50:27.000000000 +0000
+++ b/src/distrib/sets/lists/xbase/mi	2021-12-12 06:09:50.049558924 +0000
@@ -1388,6 +1388,7 @@
 ./usr/X11R7/man/cat1/xsetmode.0				xbase-xsetmode-catman	.cat,xorg
 ./usr/X11R7/man/cat1/xsetpointer.0			xbase-xsetpointer-catman	.cat,xorg
 ./usr/X11R7/man/cat1/xsetroot.0				xbase-xsetroot-catman	.cat,xorg
+./usr/X11R7/man/cat1/xsetwallpaper.0			xbase-xsetwallpaper-catman	.cat,xorg
 ./usr/X11R7/man/cat1/xsm.0				xbase-xsm-catman	.cat,xorg
 ./usr/X11R7/man/cat1/xstdcmap.0				xbase-xstdcmap-catman	.cat,xorg
 ./usr/X11R7/man/cat1/xterm.0				xbase-xterm-catman	.cat,xorg
@@ -1536,6 +1537,7 @@
 ./usr/X11R7/man/html1/xsetmode.html			xbase-xsetmode-htmlman	html,xorg
 ./usr/X11R7/man/html1/xsetpointer.html			xbase-xsetpointer-htmlman	html,xorg
 ./usr/X11R7/man/html1/xsetroot.html			xbase-xsetroot-htmlman	html,xorg
+./usr/X11R7/man/html1/xsetwallpaper.html		xbase-xsetwallpaper-htmlman	html,xorg
 ./usr/X11R7/man/html1/xsm.html				xbase-xsm-htmlman	html,xorg
 ./usr/X11R7/man/html1/xstdcmap.html			xbase-xstdcmap-htmlman	html,xorg
 ./usr/X11R7/man/html1/xterm.html			xbase-xterm-htmlman	html,xorg
@@ -1685,6 +1687,7 @@
 ./usr/X11R7/man/man1/xsetmode.1				xbase-xsetmode-man	.man,xorg
 ./usr/X11R7/man/man1/xsetpointer.1			xbase-xsetpointer-man	.man,xorg
 ./usr/X11R7/man/man1/xsetroot.1				xbase-xsetroot-man	.man,xorg
+./usr/X11R7/man/man1/xsetwallpaper.1			xbase-xsetwallpaper-man	.man,xorg
 ./usr/X11R7/man/man1/xsm.1				xbase-xsm-man	.man,xorg
 ./usr/X11R7/man/man1/xstdcmap.1				xbase-xstdcmap-man	.man,xorg
 ./usr/X11R7/man/man1/xterm.1				xbase-xterm-man	.man,xorg
diff -urN a/src/external/mit/xorg/bin/xsetwallpaper/Makefile b/src/external/mit/xorg/bin/xsetwallpaper/Makefile
--- a/src/external/mit/xorg/bin/xsetwallpaper/Makefile	2012-03-22 23:46:26.000000000 +0000
+++ b/src/external/mit/xorg/bin/xsetwallpaper/Makefile	2021-12-12 06:15:09.748507602 +0000
@@ -1,7 +1,5 @@
 #	$NetBSD: Makefile,v 1.2 2012/03/22 23:46:26 joerg Exp $
 
-NOMAN=		# defined
-
 .include <bsd.own.mk>
 
 PROG=		xsetwallpaper
@@ -12,7 +10,7 @@
 
 SRCPATH=        ${X11SRCDIR.local}/programs/xsetwallpaper
 
-LDADD+=		-lm -lX11
+LDADD+=		-lm -lX11 -lXpm
 DPADD+=		${LIBM} ${LIBX11}
 
 .PATH:		${X11SRCDIR.local}/programs/xsetwallpaper
diff -urN a/xsrc/local/programs/xsetwallpaper/xsetwallpaper.1 b/xsrc/local/programs/xsetwallpaper/xsetwallpaper.1
--- a/xsrc/local/programs/xsetwallpaper/xsetwallpaper.1	1970-01-01 00:00:00.000000000 +0000
+++ b/xsrc/local/programs/xsetwallpaper/xsetwallpaper.1	2021-12-12 05:57:25.877446559 +0000
@@ -0,0 +1,43 @@
+.\"	$NetBSD: $
+.\"
+.Dd April 25, 2021
+.Dt XSETWALLPAPER 1
+.Os
+.Sh NAME
+.Nm xsetwallpaper
+.Nd set image as wallpaper in root window
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar colour
+.Op Fl f | s | t
+.Pa filename
+.Sh DESCRIPTION
+The
+.Nm
+program loads an image as a wallpaper into the root window.
+.Pp
+Options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar colour
+Set background fill colour to
+.Ar colour.
+.It Fl f
+Fit image to screen.
+(Image aspect ratio is preserved.)
+.It Fl s
+Stretch image to screen.
+(Image aspect ratio is \fInot\fR preserved.)
+.It Fl t
+Tile image across screen.
+.El
+.Pp
+.Pa filename
+can be any of the image formats supported by the \fBstb_image\fR loader or an XPM file.
+.Sh SEE ALSO
+.Xr xsetroot 1
+.Sh AUTHORS
+.An "Jared D. McNeill" Aq Mt jmcneill%invisible.ca@localhost
+.Sh BUGS
+Only 24/32-BPP displays are supported.
+.Pp
+Image-format limitations inherited from \fBstb_image\fR are retained.
diff -urN a/xsrc/local/programs/xsetwallpaper/xsetwallpaper.c b/xsrc/local/programs/xsetwallpaper/xsetwallpaper.c
--- a/xsrc/local/programs/xsetwallpaper/xsetwallpaper.c	2020-02-08 20:29:30.000000000 +0000
+++ b/xsrc/local/programs/xsetwallpaper/xsetwallpaper.c	2021-04-28 05:32:24.000000000 +0000
@@ -31,28 +31,36 @@
 #include <sys/endian.h>
 
 #include <err.h>
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <X11/Xlib.h>
+#include <X11/xpm.h>
 
 #include "stbi.h"
 
 #define DEFAULT_FILL_COLOR	"#000000"
 
 static uint8_t *	resize_nn(const uint8_t *, int, int, int, int);
+static uint8_t *	do_fit(const uint8_t *, int *, int *, int, int, int, int);
+static uint8_t *	do_tile(const uint8_t *, int, int, int, int);
+static uint8_t *	load_image(char *, int *, int *, int *);
+static uint8_t *	load_xpm(Display *, char *, int *, int *, int *);
 
 static void
 usage(const char *pn)
 {
-	fprintf(stderr, "usage: %s [-f fillcolor] [-s] filename\n", pn);
+	fprintf(stderr, "usage: %s [-c fillcolor] [-f|-s|-t] filename\n", pn);
 	exit(EXIT_FAILURE);
 }
 
 int
 main(int argc, char *argv[])
 {
+	enum dispmode { NONE = 0, FIT, STRETCH, TILE };
 	const char *fill_color = DEFAULT_FILL_COLOR;
 	const char *pn = argv[0];
 	uint8_t *data;
@@ -60,9 +68,9 @@
 	int root_x, root_y;
 	int bitmap_pad, srcx, srcy, dstx, dsty;
 	int imagew, imageh, imagebpp;
-	int ch, i;
+	int ch;
 	int screen, default_depth, byte_order;
-	int scale = 0;
+	enum dispmode mode = NONE;
 	Display *display;
 	Colormap colormap;
 	XImage *image;
@@ -71,13 +79,19 @@
 	Window window;
 	GC gc;
 
-	while ((ch = getopt(argc, argv, "f:sh")) != -1) {
+	while ((ch = getopt(argc, argv, "c:hfst")) != -1) {
 		switch (ch) {
-		case 'f':
+		case 'c':
 			fill_color = optarg;
 			break;
-		case 's':
-			scale = 1;
+		case 'f':	/* fit to screen--preserves aspect-ratio */
+			mode = FIT;
+			break;
+		case 's':	/* stretch image--does not preserve AR */
+			mode = STRETCH;
+			break;
+		case 't':	/* tile image across screen */
+			mode = TILE;
 			break;
 		case 'h':
 		default:
@@ -87,34 +101,10 @@
 	}
 	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;
-	}
-
-#if _BYTE_ORDER == _BIG_ENDIAN
-	for (i = 0; i < imagew * imageh * 4; i += 4) {
-		uint32_t *p = (uint32_t *)&data[i];
-		*p = bswap32(*p);
-	}
-#endif
-
-#ifdef DEBUG
-	printf("%s: %dx%d %dbpp\n", argv[0], imagew, imageh, imagebpp * 8);
-#endif
-
 	/* open the display */
 	display = XOpenDisplay(NULL);
 	if (display == NULL) {
@@ -130,7 +120,7 @@
 	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");
+		errx(EXIT_FAILURE, "couldn't get screen dimensions");
 	}
 
 #ifdef DEBUG
@@ -139,12 +129,41 @@
 
 	XSync(display, False);
 
-	if (scale) {
+	/* Load the image */
+	data = load_image(argv[0], &imagew, &imageh, &imagebpp);
+	if (data == NULL) {
+		data = load_xpm(display, argv[0], &imagew, &imageh, &imagebpp);
+		if (data == NULL)
+			errx(EXIT_FAILURE, "failed to load %s", argv[0]);
+	}
+
+	switch (mode) {
+	case FIT: {
+		int new_w, new_h;
+		data = do_fit(data, &new_w, &new_h, imagew, imageh,
+				root_width, root_height);
+		if (data == NULL)
+			err(EXIT_FAILURE, "couldn't fit image.");
+		imagew = new_w;
+		imageh = new_h;
+		break;
+	}
+	case STRETCH:
 		data = resize_nn(data, imagew, imageh, root_width, root_height);
 		if (data == NULL)
-			err(EXIT_FAILURE, "couldn't resize image\n");
+			err(EXIT_FAILURE, "couldn't stretch image.");
+		imagew = root_width;
+		imageh = root_height;
+		break;
+	case TILE:
+		data = do_tile(data, imagew, imageh, root_width, root_height);
+		if (data == NULL)
+			err(EXIT_FAILURE, "couldn't tile image.");
 		imagew = root_width;
 		imageh = root_height;
+		break;
+	case NONE:
+		break;
 	}
 
 	/* Parse the fill colour and allocate it */
@@ -179,9 +198,9 @@
 
 	/* Fill the background with the specified fill colour */
 	XSetForeground(display, gc, color.pixel);
-	XFillRectangle(display, pixmap, gc, 0, 0, root_width, root_height); 
+	XFillRectangle(display, pixmap, gc, 0, 0, root_width, root_height);
 
-	/* Copy the image to the pixmal, centering it on screen */
+	/* Copy the image to the pixmap, centering it on screen */
 	if ((unsigned int)imagew > root_width) {
 		srcx = (imagew - root_width) / 2;
 		dstx = 0;
@@ -219,7 +238,7 @@
 	int src_x, src_y, dst_x, dst_y;
 
 	src = (const uint32_t *)data;
-	dst = malloc(src_w * src_h * 4);
+	dst = malloc(dst_w * dst_h * 4);
 	if (dst == NULL)
 		return NULL;
 
@@ -233,3 +252,143 @@
 
 	return (uint8_t *)dst;
 }
+
+static uint8_t *
+load_image(char* fn, int *imagew, int *imageh, int *imagebpp)
+{
+	uint8_t *data;
+	int i;
+
+	data = stbi_load(fn, imagew, imageh, imagebpp, 4);
+	if (data == NULL)
+		return NULL;
+
+	/* 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;
+	}
+#if _BYTE_ORDER == _BIG_ENDIAN
+	for (i = 0; i < *imagew * *imageh * 4; i += 4) {
+		uint32_t *p = (uint32_t *)&data[i];
+		*p = bswap32(*p);
+	}
+#endif
+#ifdef DEBUG
+	printf("%s: %dx%d %dbpp\n", fn, *imagew, *imageh, *imagebpp * 8);
+#endif
+	return data;
+}
+
+static uint8_t *
+load_xpm(Display *display, char *fn, int *imagew, int *imageh, int *imagebpp)
+{
+	XpmAttributes *attr;
+	XImage *image;
+	uint32_t *data;
+	size_t size;
+	int x, y;
+
+	size = XpmAttributesSize();
+	attr = malloc(size);
+	if (attr == NULL)
+		return NULL;
+
+	memset(attr, 0, size);
+	attr->valuemask = XpmBitmapFormat | XpmColorKey;
+	attr->bitmap_format = ZPixmap;
+	attr->color_key = XPM_COLOR;
+	
+	if (XpmReadFileToImage(display, fn, &image, NULL, attr) != XpmSuccess)
+		return NULL;
+	
+#ifdef DEBUG
+	printf("%s:\n", fn);
+	printf("width: %d\n", image->width);
+	printf("height: %d\n", image->height);
+	printf("depth: %d\n", image->depth);
+	printf("xoffset: %d\n", image->xoffset);
+	printf("format: %s\n", image->format == ZPixmap ? "ZPixmap" : "Unk");
+	printf("byte_order: %s\n", image->byte_order == LSBFirst ? "LSB" : "MSB");
+	printf("bit_order: %s\n", image->bitmap_bit_order == LSBFirst ? "LSB" : "MSB");
+	printf("bitmap_unit: %d\n", image->bitmap_unit);
+	printf("bitmap_pad: %d\n", image->bitmap_pad);
+	printf("bytes_per_line: %d\n", image->bytes_per_line);
+	printf("bits_per_pixel: %d\n", image->bits_per_pixel);
+#endif
+	*imagew = image->width;
+	*imageh = image->height;
+	*imagebpp = image->depth / 8;
+	data = malloc(*imagew * *imageh * 4);
+	if (data == NULL)
+		return NULL;
+	for (y = 0; y < *imageh; y++) {
+		for (x = 0; x < *imagew; x++) {
+			data[y * *imagew + x] = XGetPixel(image, x, y);
+		}
+	}
+	XpmFreeAttributes(attr);
+	XDestroyImage(image);
+
+	return (uint8_t *)data;
+}
+
+static uint8_t *
+do_fit(const uint8_t *data,
+	int *new_w, int *new_h,
+	int src_w, int src_h,
+	int dst_w, int dst_h)
+{
+	double scale, scale_w, scale_h;
+
+	scale_w = (double)dst_w / (double)src_w;
+	scale_h = (double)dst_h / (double)src_h;
+	scale = (scale_w > scale_h) ? scale_h : scale_w;
+	*new_w = (int)floor((double)src_w * scale);
+	*new_h = (int)floor((double)src_h * scale);
+
+#ifdef DEBUG
+	printf("orig=%dx%d, new=%dx%d\n", src_w, src_h, *new_w, *new_h);
+#endif
+	return resize_nn(data, src_w, src_h, *new_w, *new_h);
+}
+
+static uint8_t *
+do_tile(const uint8_t *data, int src_w, int src_h, int dst_w, int dst_h)
+{
+	const uint32_t *src;
+	uint32_t *dst;
+	void* buf = NULL;	/* used only if we resize */
+	int new_w, new_h, src_x, src_y, dst_x, dst_y;
+
+	dst = malloc(dst_w * dst_h * 4);
+	if (dst == NULL)
+		return NULL;
+
+	/* resize if needed first */
+	if (src_w > dst_w || src_h > dst_h) {
+		buf = do_fit(data, &new_w, &new_h, src_w, src_h, dst_w, dst_h);
+		if (buf == NULL) {
+			free(dst);
+			return NULL;
+		}
+		/* override */
+		src_w = new_w;
+		src_h = new_h;
+		src = (const uint32_t *)buf;
+	} else
+		src = (const uint32_t *)data;
+
+	for (src_y = dst_y = 0; dst_y < dst_h; src_y++, dst_y++) {
+		src_y = src_y % src_h;
+		for (src_x = dst_x = 0; dst_x < dst_w; src_x++, dst_x++) {
+			src_x = src_x % src_w;
+			dst[dst_y * dst_w + dst_x] = src[src_y * src_w + src_x];
+		}
+	}
+
+	free(buf);		/* free resized tmp. image if any */
+	return (uint8_t *)dst;
+}


Home | Main Index | Thread Index | Old Index