NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
xsrc/58580: xsetwallpaper(1): bug fix + enhancements
>Number: 58580
>Category: xsrc
>Synopsis: xsetwallpaper(1): bug fix + enhancements
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: xsrc-manager
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Aug 11 06:40:00 +0000 2024
>Originator: RVP
>Release: NetBSD/amd64 10.99.11
>Organization:
>Environment:
NetBSD/amd64 10.99.11
>Description:
Slightly updated version of the patch submitted here originally:
https://mail-index.netbsd.org/tech-x11/2021/12/12/msg002259.html
but, forgotten by everybody (incl. me)...
>How-To-Repeat:
As in the URL.
>Fix:
Man-page may need minor adjustment.
---START patch---
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.000000000 +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.000000000 +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-13 22:26:53.864090669 +0000
@@ -0,0 +1,67 @@
+.\" $NetBSD: $
+.\"
+.\" License: Public Domain
+.\"
+.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 indent
+.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
+.Em not
+preserved.)
+.It Fl t
+Tile image across screen.
+.El
+.Pp
+.Pa filename
+can be any of the following image formats:
+.Bl -tag -width indent
+.It BMP
+non-1bpp, non-RLE
+.It GIF
+.It HDR
+radiance rgbE format
+.It JPEG
+Baseline only (no progressive)
+.It PIC
+Softimage PIC
+.It PNG
+8-bit only
+.It PSD
+composited view only, no extra channels
+.It TGA
+(not sure what subset, if a subset)
+.It XPM
+.El
+.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
+.Li stb_image
+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-12-13 23:17:21.241966088 +0000
@@ -31,38 +31,46 @@
#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;
+ uint8_t *data, *d;
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 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,50 @@
XSync(display, False);
- if (scale) {
- data = resize_nn(data, imagew, imageh, root_width, root_height);
+ /* 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)
- err(EXIT_FAILURE, "couldn't resize image\n");
+ errx(EXIT_FAILURE, "failed to load %s", argv[0]);
+ }
+
+ switch (mode) {
+ case FIT: {
+ int new_w, new_h;
+ d = do_fit(data, &new_w, &new_h, imagew, imageh,
+ root_width, root_height);
+ if (d == NULL) {
+ free(data);
+ err(EXIT_FAILURE, "couldn't fit image.");
+ }
+ data = d;
+ imagew = new_w;
+ imageh = new_h;
+ break;
+ }
+ case STRETCH:
+ d = resize_nn(data, imagew, imageh, root_width, root_height);
+ if (d == NULL) {
+ free(data);
+ err(EXIT_FAILURE, "couldn't stretch image.");
+ }
+ data = d;
+ imagew = root_width;
+ imageh = root_height;
+ break;
+ case TILE:
+ d = do_tile(data, imagew, imageh, root_width, root_height);
+ if (d == NULL) {
+ free(data);
+ err(EXIT_FAILURE, "couldn't tile image.");
+ }
+ data = d;
imagew = root_width;
imageh = root_height;
+ break;
+ case NONE:
+ break;
}
/* Parse the fill colour and allocate it */
@@ -164,9 +192,8 @@
bitmap_pad = 8;
image = XCreateImage(display, CopyFromParent, default_depth,
ZPixmap, 0, (char *)data, imagew, imageh, bitmap_pad, 0);
- if (image == NULL) {
+ if (image == NULL)
errx(EXIT_FAILURE, "XCreateImage failed");
- }
XInitImage(image);
image->byte_order = byte_order;
@@ -179,9 +206,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;
@@ -206,6 +233,8 @@
/* Cleanup */
XFreePixmap(display, pixmap);
+ XFreeGC(display, gc);
+ XDestroyImage(image);
XCloseDisplay(display);
return EXIT_SUCCESS;
@@ -219,7 +248,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;
@@ -231,5 +260,155 @@
}
}
+ free((void *)src);
+ 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) {
+ XpmFreeAttributes(attr);
+ free(attr);
+ 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) {
+ XpmFreeAttributes(attr);
+ free(attr);
+ 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);
+ free(attr);
+
+ 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;
+ }
+ data = NULL; /* already freed by resize_nn() */
+ /* 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 */
+ free((void *)data); /* free orig. image if any */
return (uint8_t *)dst;
}
---END patch---
Home |
Main Index |
Thread Index |
Old Index