sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit bc7b57379bce0e7f7b3a974724e0f1a1c754a190
parent 24e1c6729e3c24b178b16fccba5dcb52b6e99388
Author: Matthias Schoth <mschoth@gmail.com>
Date:   Sat, 31 Oct 2026 22:45:35 +0100

[st][patches][background_image] Fix 0.9.3 X client and 0.8.x leaks

- 0.9.3: publish the new pixmap before killing the previous owner; only
  one retained client/pixmap remains, so repeated updates no longer clog
  the X connection or exhaust client slots.
- 0.8.4/0.8.5: free the previous GC and pixmap on reload; failed loads
  keep the current background, and loader error paths no longer leak.
- USR1 reload: use sigaction() and a self-pipe, reloading from the main
  loop instead of calling Xlib in the signal handler. Applies to 0.8.4
  and 0.8.5.

Diffstat:
Mst.suckless.org/patches/background_image/st-background-image-0.8.4.diff | 121++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mst.suckless.org/patches/background_image/st-background-image-0.8.5.diff | 119++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mst.suckless.org/patches/background_image/st-background-image-0.9.3.diff | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mst.suckless.org/patches/background_image/st-background-image-signal-reload-0.8.5.diff | 115++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
4 files changed, 320 insertions(+), 124 deletions(-)

diff --git a/st.suckless.org/patches/background_image/st-background-image-0.8.4.diff b/st.suckless.org/patches/background_image/st-background-image-0.8.4.diff @@ -1,12 +1,12 @@ -From 2c984d74ca15806dcfa174b7e75f48c0d01a49bf Mon Sep 17 00:00:00 2001 +From ac472ae8b588b8ef6be7cbdd4487210f07349a3c Mon Sep 17 00:00:00 2001 From: Matthias Schoth <mschoth@gmail.com> Date: Thu, 17 Feb 2022 00:23:23 +0100 Subject: [PATCH] Implements background image and pseudo transparancy support. --- config.def.h | 8 +++ - x.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++---- - 2 files changed, 139 insertions(+), 10 deletions(-) + x.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 166 insertions(+), 10 deletions(-) diff --git a/config.def.h b/config.def.h index 6f05dce..3d352db 100644 @@ -28,7 +28,7 @@ index 6f05dce..3d352db 100644 * What program is execed by st depends of these precedence rules: * 1: program passed with -e diff --git a/x.c b/x.c -index 210f184..5ecb8e5 100644 +index 210f184..a5fc827 100644 --- a/x.c +++ b/x.c @@ -14,6 +14,7 @@ @@ -47,15 +47,16 @@ index 210f184..5ecb8e5 100644 int ch; /* char height */ int cw; /* char width */ int mode; /* window state/mode flags */ -@@ -101,6 +103,7 @@ typedef struct { +@@ -101,6 +103,8 @@ typedef struct { XVaNestedList spotlist; } ime; Draw draw; + GC bggc; /* Graphics Context for background */ ++ Pixmap bgpmap; /* background image pixmap */ Visual *vis; XSetWindowAttributes attrs; int scr; -@@ -151,6 +154,9 @@ static void ximinstantiate(Display *, XPointer, XPointer); +@@ -151,6 +155,9 @@ static void ximinstantiate(Display *, XPointer, XPointer); static void ximdestroy(XIM, XPointer, XPointer); static int xicdestroy(XIC, XPointer, XPointer); static void xinit(int, int); @@ -65,7 +66,7 @@ index 210f184..5ecb8e5 100644 static void cresize(int, int); static void xresize(int, int); static void xhints(void); -@@ -502,6 +508,12 @@ propnotify(XEvent *e) +@@ -502,6 +509,12 @@ propnotify(XEvent *e) xpev->atom == clipboard)) { selnotify(e); } @@ -78,7 +79,7 @@ index 210f184..5ecb8e5 100644 } void -@@ -532,7 +544,8 @@ selnotify(XEvent *e) +@@ -532,7 +545,8 @@ selnotify(XEvent *e) return; } @@ -88,7 +89,7 @@ index 210f184..5ecb8e5 100644 /* * If there is some PropertyNotify with no data, then * this is the signal of the selection owner that all -@@ -550,9 +563,11 @@ selnotify(XEvent *e) +@@ -550,9 +564,11 @@ selnotify(XEvent *e) * when the selection owner does send us the next * chunk of data. */ @@ -102,7 +103,7 @@ index 210f184..5ecb8e5 100644 /* * Deleting the property is the transfer start signal. -@@ -820,9 +835,9 @@ xsetcolorname(int x, const char *name) +@@ -820,9 +836,9 @@ xsetcolorname(int x, const char *name) void xclear(int x1, int y1, int x2, int y2) { @@ -115,7 +116,7 @@ index 210f184..5ecb8e5 100644 } void -@@ -1207,6 +1222,100 @@ xinit(int cols, int rows) +@@ -1207,6 +1223,126 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } @@ -134,44 +135,53 @@ index 210f184..5ecb8e5 100644 +loadff(const char *filename) +{ + uint32_t i, hdr[4], w, h, size; -+ uint64_t *data; -+ FILE *f = fopen(filename, "rb"); ++ uint64_t npixels, *data; ++ FILE *f; ++ XImage *xi; + -+ if (f == NULL) { ++ if (!(f = fopen(filename, "rb"))) { + fprintf(stderr, "could not load background image.\n"); + return NULL; + } + -+ if (fread(hdr, sizeof(*hdr), LEN(hdr), f) != LEN(hdr)) -+ if (ferror(f)) { -+ fprintf(stderr, "fread:"); -+ return NULL; -+ } -+ else { -+ fprintf(stderr, "fread: Unexpected end of file\n"); -+ return NULL; -+ } ++ if (fread(hdr, sizeof(*hdr), LEN(hdr), f) != LEN(hdr)) { ++ fprintf(stderr, "fread: %s\n", ferror(f) ? "read error" : ++ "unexpected end of file"); ++ fclose(f); ++ return NULL; ++ } + + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { -+ fprintf(stderr, "Invalid magic value"); ++ fprintf(stderr, "Invalid magic value\n"); ++ fclose(f); + return NULL; + } + + w = ntohl(hdr[2]); + h = ntohl(hdr[3]); ++ npixels = (uint64_t)w * h; ++ if (w == 0 || h == 0 || w > INT_MAX / 8 || ++ npixels > UINT32_MAX || npixels > SIZE_MAX / sizeof(*data)) { ++ fprintf(stderr, "Invalid image dimensions\n"); ++ fclose(f); ++ return NULL; ++ } + size = w * h; -+ data = malloc(size * sizeof(uint64_t)); + -+ if (fread(data, sizeof(uint64_t), size, f) != size) -+ if (ferror(f)) { -+ fprintf(stderr, "fread:"); -+ return NULL; -+ } -+ else { -+ fprintf(stderr, "fread: Unexpected end of file"); -+ return NULL; -+ } ++ data = malloc(size * sizeof(*data)); ++ if (!data) { ++ fprintf(stderr, "malloc: %s\n", strerror(errno)); ++ fclose(f); ++ return NULL; ++ } + ++ if (fread(data, sizeof(*data), size, f) != size) { ++ fprintf(stderr, "fread: %s\n", ferror(f) ? "read error" : ++ "unexpected end of file"); ++ free(data); ++ fclose(f); ++ return NULL; ++ } + fclose(f); + + for (i = 0; i < size; i++) @@ -179,9 +189,13 @@ index 210f184..5ecb8e5 100644 + (data[i] & 0x0000000000FF0000) >> 8 | + (data[i] & 0x000000FF00000000) >> 32; + -+ XImage *xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr), -+ DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0, -+ (char *)data, w, h, 32, w * 8); ++ xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr), ++ DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0, ++ (char *)data, w, h, 32, w * 8); ++ if (!xi) { ++ free(data); ++ return NULL; ++ } + xi->bits_per_pixel = 64; + return xi; +} @@ -193,18 +207,31 @@ index 210f184..5ecb8e5 100644 +bginit() +{ + XGCValues gcvalues; -+ Drawable bgimg; + XImage *bgxi = loadff(bgfile); + ++ if (!bgxi) { ++ if (xw.bggc) ++ return; ++ memset(&gcvalues, 0, sizeof(gcvalues)); ++ xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues); ++ XSetForeground(xw.dpy, xw.bggc, dc.col[defaultbg].pixel); ++ XSetFillStyle(xw.dpy, xw.bggc, FillSolid); ++ return; ++ } ++ ++ if (xw.bggc) ++ XFreeGC(xw.dpy, xw.bggc); ++ if (xw.bgpmap) ++ XFreePixmap(xw.dpy, xw.bgpmap); ++ + memset(&gcvalues, 0, sizeof(gcvalues)); + xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues); -+ if (!bgxi) return; -+ bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height, -+ DefaultDepth(xw.dpy, xw.scr)); -+ XPutImage(xw.dpy, bgimg, dc.gc, bgxi, 0, 0, 0, 0, bgxi->width, ++ xw.bgpmap = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height, ++ DefaultDepth(xw.dpy, xw.scr)); ++ XPutImage(xw.dpy, xw.bgpmap, dc.gc, bgxi, 0, 0, 0, 0, bgxi->width, + bgxi->height); + XDestroyImage(bgxi); -+ XSetTile(xw.dpy, xw.bggc, bgimg); ++ XSetTile(xw.dpy, xw.bggc, xw.bgpmap); + XSetFillStyle(xw.dpy, xw.bggc, FillTiled); + if (pseudotransparency) { + updatexy(); @@ -216,7 +243,7 @@ index 210f184..5ecb8e5 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -@@ -1447,7 +1556,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i +@@ -1447,7 +1583,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i xclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ @@ -228,7 +255,7 @@ index 210f184..5ecb8e5 100644 /* Set the clip region because Xft is sometimes dirty. */ r.x = 0; -@@ -1855,9 +1967,17 @@ cmessage(XEvent *e) +@@ -1855,9 +1994,17 @@ cmessage(XEvent *e) void resize(XEvent *e) { @@ -249,7 +276,7 @@ index 210f184..5ecb8e5 100644 cresize(e->xconfigure.width, e->xconfigure.height); } -@@ -2041,6 +2161,7 @@ run: +@@ -2041,6 +2188,7 @@ run: rows = MAX(rows, 1); tnew(cols, rows); xinit(cols, rows); @@ -258,5 +285,5 @@ index 210f184..5ecb8e5 100644 selinit(); run(); -- -2.35.1 +2.55.0 diff --git a/st.suckless.org/patches/background_image/st-background-image-0.8.5.diff b/st.suckless.org/patches/background_image/st-background-image-0.8.5.diff @@ -1,12 +1,12 @@ -From 4ce17bbc340ca1f93f9be686f4a796797f9ca6d5 Mon Sep 17 00:00:00 2001 +From d9f5d917ac2016f3f375f4ada575e6b6fc5e2d1b Mon Sep 17 00:00:00 2001 From: Matthias Schoth <mschoth@gmail.com> Date: Sat, 16 Apr 2022 14:21:22 +0200 Subject: [PATCH] Implements background image and pseudo transparancy support. --- config.def.h | 8 +++ - x.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++---- - 2 files changed, 139 insertions(+), 10 deletions(-) + x.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 166 insertions(+), 10 deletions(-) diff --git a/config.def.h b/config.def.h index 91ab8ca..ad19e3d 100644 @@ -28,7 +28,7 @@ index 91ab8ca..ad19e3d 100644 * What program is execed by st depends of these precedence rules: * 1: program passed with -e diff --git a/x.c b/x.c -index 8a16faa..fedef53 100644 +index 8a16faa..cab0058 100644 --- a/x.c +++ b/x.c @@ -14,6 +14,7 @@ @@ -47,15 +47,16 @@ index 8a16faa..fedef53 100644 int ch; /* char height */ int cw; /* char width */ int mode; /* window state/mode flags */ -@@ -101,6 +103,7 @@ typedef struct { +@@ -101,6 +103,8 @@ typedef struct { XVaNestedList spotlist; } ime; Draw draw; + GC bggc; /* Graphics Context for background */ ++ Pixmap bgpmap; /* background image pixmap */ Visual *vis; XSetWindowAttributes attrs; int scr; -@@ -151,6 +154,9 @@ static void ximinstantiate(Display *, XPointer, XPointer); +@@ -151,6 +155,9 @@ static void ximinstantiate(Display *, XPointer, XPointer); static void ximdestroy(XIM, XPointer, XPointer); static int xicdestroy(XIC, XPointer, XPointer); static void xinit(int, int); @@ -65,7 +66,7 @@ index 8a16faa..fedef53 100644 static void cresize(int, int); static void xresize(int, int); static void xhints(void); -@@ -504,6 +510,12 @@ propnotify(XEvent *e) +@@ -504,6 +511,12 @@ propnotify(XEvent *e) xpev->atom == clipboard)) { selnotify(e); } @@ -78,7 +79,7 @@ index 8a16faa..fedef53 100644 } void -@@ -534,7 +546,8 @@ selnotify(XEvent *e) +@@ -534,7 +547,8 @@ selnotify(XEvent *e) return; } @@ -88,7 +89,7 @@ index 8a16faa..fedef53 100644 /* * If there is some PropertyNotify with no data, then * this is the signal of the selection owner that all -@@ -552,9 +565,11 @@ selnotify(XEvent *e) +@@ -552,9 +566,11 @@ selnotify(XEvent *e) * when the selection owner does send us the next * chunk of data. */ @@ -102,7 +103,7 @@ index 8a16faa..fedef53 100644 /* * Deleting the property is the transfer start signal. -@@ -835,9 +850,9 @@ xsetcolorname(int x, const char *name) +@@ -835,9 +851,9 @@ xsetcolorname(int x, const char *name) void xclear(int x1, int y1, int x2, int y2) { @@ -115,7 +116,7 @@ index 8a16faa..fedef53 100644 } void -@@ -1223,6 +1238,100 @@ xinit(int cols, int rows) +@@ -1223,6 +1239,126 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } @@ -134,44 +135,53 @@ index 8a16faa..fedef53 100644 +loadff(const char *filename) +{ + uint32_t i, hdr[4], w, h, size; -+ uint64_t *data; -+ FILE *f = fopen(filename, "rb"); ++ uint64_t npixels, *data; ++ FILE *f; ++ XImage *xi; + -+ if (f == NULL) { ++ if (!(f = fopen(filename, "rb"))) { + fprintf(stderr, "Can not open background image file\n"); + return NULL; + } + -+ if (fread(hdr, sizeof(*hdr), LEN(hdr), f) != LEN(hdr)) -+ if (ferror(f)) { -+ fprintf(stderr, "fread:"); -+ return NULL; -+ } -+ else { -+ fprintf(stderr, "fread: Unexpected end of file\n"); -+ return NULL; -+ } ++ if (fread(hdr, sizeof(*hdr), LEN(hdr), f) != LEN(hdr)) { ++ fprintf(stderr, "fread: %s\n", ferror(f) ? "read error" : ++ "unexpected end of file"); ++ fclose(f); ++ return NULL; ++ } + + if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) { + fprintf(stderr, "Invalid magic value\n"); ++ fclose(f); + return NULL; + } + + w = ntohl(hdr[2]); + h = ntohl(hdr[3]); ++ npixels = (uint64_t)w * h; ++ if (w == 0 || h == 0 || w > INT_MAX / 8 || ++ npixels > UINT32_MAX || npixels > SIZE_MAX / sizeof(*data)) { ++ fprintf(stderr, "Invalid image dimensions\n"); ++ fclose(f); ++ return NULL; ++ } + size = w * h; -+ data = malloc(size * sizeof(uint64_t)); + -+ if (fread(data, sizeof(uint64_t), size, f) != size) -+ if (ferror(f)) { -+ fprintf(stderr, "fread:"); -+ return NULL; -+ } -+ else { -+ fprintf(stderr, "fread: Unexpected end of file\n"); -+ return NULL; -+ } ++ data = malloc(size * sizeof(*data)); ++ if (!data) { ++ fprintf(stderr, "malloc: %s\n", strerror(errno)); ++ fclose(f); ++ return NULL; ++ } + ++ if (fread(data, sizeof(*data), size, f) != size) { ++ fprintf(stderr, "fread: %s\n", ferror(f) ? "read error" : ++ "unexpected end of file"); ++ free(data); ++ fclose(f); ++ return NULL; ++ } + fclose(f); + + for (i = 0; i < size; i++) @@ -179,9 +189,13 @@ index 8a16faa..fedef53 100644 + (data[i] & 0x0000000000FF0000) >> 8 | + (data[i] & 0x000000FF00000000) >> 32; + -+ XImage *xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr), -+ DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0, -+ (char *)data, w, h, 32, w * 8); ++ xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr), ++ DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0, ++ (char *)data, w, h, 32, w * 8); ++ if (!xi) { ++ free(data); ++ return NULL; ++ } + xi->bits_per_pixel = 64; + return xi; +} @@ -193,18 +207,31 @@ index 8a16faa..fedef53 100644 +bginit() +{ + XGCValues gcvalues; -+ Drawable bgimg; + XImage *bgxi = loadff(bgfile); + ++ if (!bgxi) { ++ if (xw.bggc) ++ return; ++ memset(&gcvalues, 0, sizeof(gcvalues)); ++ xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues); ++ XSetForeground(xw.dpy, xw.bggc, dc.col[defaultbg].pixel); ++ XSetFillStyle(xw.dpy, xw.bggc, FillSolid); ++ return; ++ } ++ ++ if (xw.bggc) ++ XFreeGC(xw.dpy, xw.bggc); ++ if (xw.bgpmap) ++ XFreePixmap(xw.dpy, xw.bgpmap); ++ + memset(&gcvalues, 0, sizeof(gcvalues)); + xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues); -+ if (!bgxi) return; -+ bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height, -+ DefaultDepth(xw.dpy, xw.scr)); -+ XPutImage(xw.dpy, bgimg, dc.gc, bgxi, 0, 0, 0, 0, bgxi->width, ++ xw.bgpmap = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height, ++ DefaultDepth(xw.dpy, xw.scr)); ++ XPutImage(xw.dpy, xw.bgpmap, dc.gc, bgxi, 0, 0, 0, 0, bgxi->width, + bgxi->height); + XDestroyImage(bgxi); -+ XSetTile(xw.dpy, xw.bggc, bgimg); ++ XSetTile(xw.dpy, xw.bggc, xw.bgpmap); + XSetFillStyle(xw.dpy, xw.bggc, FillTiled); + if (pseudotransparency) { + updatexy(); @@ -216,7 +243,7 @@ index 8a16faa..fedef53 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -@@ -1463,7 +1572,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i +@@ -1463,7 +1599,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i xclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ @@ -228,7 +255,7 @@ index 8a16faa..fedef53 100644 /* Set the clip region because Xft is sometimes dirty. */ r.x = 0; -@@ -1886,9 +1998,17 @@ cmessage(XEvent *e) +@@ -1886,9 +2025,17 @@ cmessage(XEvent *e) void resize(XEvent *e) { @@ -249,7 +276,7 @@ index 8a16faa..fedef53 100644 cresize(e->xconfigure.width, e->xconfigure.height); } -@@ -2072,6 +2192,7 @@ run: +@@ -2072,6 +2219,7 @@ run: rows = MAX(rows, 1); tnew(cols, rows); xinit(cols, rows); @@ -258,5 +285,5 @@ index 8a16faa..fedef53 100644 selinit(); run(); -- -2.35.1 +2.55.0 diff --git a/st.suckless.org/patches/background_image/st-background-image-0.9.3.diff b/st.suckless.org/patches/background_image/st-background-image-0.9.3.diff @@ -1,6 +1,6 @@ -From b43b4842d62d800da712ef7d6244967daa4ff096 Mon Sep 17 00:00:00 2001 +From c2ae9bfcb131b13435398922b1baf88c87df8908 Mon Sep 17 00:00:00 2001 From: Matthias Schoth <mschoth@gmail.com> -Date: Tue, 18 Aug 2026 19:32:18 +0200 +Date: Sat, 31 Oct 2026 22:41:01 +0100 Subject: [PATCH] Add background image support via root window pixmap Add a background image to st by tiling a server-side pixmap set as the @@ -17,13 +17,19 @@ stbg reads a farbfeld image from a file or stdin (using -) and sets the property. It is not built by default; compile separately with: cc -o stbg stbg.c -lX11 + +A new image is decoded and published before the previous owner is +released, so a failed read leaves the current background untouched. +Only the current pixmap is kept alive; replacing the background kills +the client that owns the previous one, so periodic updates do not +accumulate X clients or server-side image memory. --- - config.def.h | 6 +++ + config.def.h | 6 ++ st.c | 2 +- st.h | 1 + - stbg.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ - x.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++---- - 5 files changed, 248 insertions(+), 10 deletions(-) + stbg.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++ + x.c | 127 +++++++++++++++++++++++++++++++++--- + 5 files changed, 305 insertions(+), 10 deletions(-) create mode 100644 stbg.c diff --git a/config.def.h b/config.def.h @@ -70,13 +76,14 @@ index fd3b0d8..a716a73 100644 int ttynew(const char *, char *, const char *, char **); diff --git a/stbg.c b/stbg.c new file mode 100644 -index 0000000..80bc4cf +index 0000000..ed9c2fa --- /dev/null +++ b/stbg.c -@@ -0,0 +1,122 @@ +@@ -0,0 +1,179 @@ +/* See LICENSE file for copyright and license details. */ +/* Build: cc -o stbg stbg.c -lX11 */ +#include <errno.h> ++#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> @@ -88,6 +95,7 @@ index 0000000..80bc4cf +#include <X11/Xatom.h> + +static char *argv0; ++static int xerror(Display *dpy, XErrorEvent *e) { (void)dpy; (void)e; return 0; } + +static void +die(const char *errstr, ...) @@ -107,15 +115,52 @@ index 0000000..80bc4cf + die("usage: %s file.ff\n %s - < file.ff\n", argv0, argv0); +} + ++static Pixmap ++getprev(Display *dpy, Window root) ++{ ++ Atom prop = XInternAtom(dpy, "_ST_BACKGROUND_IMAGE", True); ++ Atom actual_type; ++ int actual_format; ++ unsigned long nitems, bytes_after; ++ unsigned char *prop_data = NULL; ++ Pixmap prev = None; ++ ++ if (prop == None) ++ return None; ++ if (XGetWindowProperty(dpy, root, prop, 0, 1, False, XA_PIXMAP, ++ &actual_type, &actual_format, &nitems, ++ &bytes_after, &prop_data) != Success) ++ return None; ++ if (prop_data && nitems == 1 && actual_type == XA_PIXMAP && actual_format == 32) ++ prev = *(Pixmap *)prop_data; ++ if (prop_data) ++ XFree(prop_data); ++ return prev; ++} ++ ++static void ++killprev(Display *dpy, Pixmap prev) ++{ ++ XErrorHandler oldh; ++ ++ if (prev == None) ++ return; ++ oldh = XSetErrorHandler(xerror); ++ XKillClient(dpy, prev); ++ XSync(dpy, False); ++ XSetErrorHandler(oldh); ++} ++ +int +main(int argc, char *argv[]) +{ + uint32_t i, hdr[4], w, h, size; ++ uint64_t npixels; + uint64_t *data; + uint32_t *data32; + FILE *f; + int fromstdin; -+ Pixmap pmap; ++ Pixmap pmap, prev; + Display *dpy; + Window root; + int scr; @@ -148,7 +193,9 @@ index 0000000..80bc4cf + + w = ntohl(hdr[2]); + h = ntohl(hdr[3]); -+ if (w == 0 || h == 0) ++ npixels = (uint64_t)w * h; ++ if (w == 0 || h == 0 || w > INT_MAX / 4 || ++ npixels > UINT32_MAX || npixels > SIZE_MAX / sizeof(uint64_t)) + die("invalid farbfeld dimensions\n"); + size = w * h; + @@ -156,14 +203,18 @@ index 0000000..80bc4cf + if (!data) + die("malloc: %s\n", strerror(errno)); + -+ if (fread(data, sizeof(uint64_t), size, f) != size) ++ if (fread(data, sizeof(uint64_t), size, f) != size) { ++ free(data); + die("fread: unexpected end of file\n"); ++ } + if (!fromstdin) + fclose(f); + + data32 = malloc(size * sizeof(uint32_t)); -+ if (!data32) ++ if (!data32) { ++ free(data); + die("malloc: %s\n", strerror(errno)); ++ } + + for (i = 0; i < size; i++) { + uint64_t p = data[i]; @@ -176,8 +227,16 @@ index 0000000..80bc4cf + xi = XCreateImage(dpy, DefaultVisual(dpy, scr), + DefaultDepth(dpy, scr), ZPixmap, 0, + (char *)data32, w, h, 32, w * 4); ++ if (!xi) { ++ free(data32); ++ die("XCreateImage failed\n"); ++ } + + pmap = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, scr)); ++ if (!pmap) { ++ XDestroyImage(xi); ++ die("XCreatePixmap failed\n"); ++ } + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; @@ -187,12 +246,16 @@ index 0000000..80bc4cf + XDestroyImage(xi); + XFreeGC(dpy, gc); + ++ prev = getprev(dpy, root); ++ ++ XSetCloseDownMode(dpy, RetainPermanent); + atom_stbg = XInternAtom(dpy, "_ST_BACKGROUND_IMAGE", False); + XChangeProperty(dpy, root, atom_stbg, XA_PIXMAP, 32, + PropModeReplace, (unsigned char *)&pmap, 1); -+ XSetCloseDownMode(dpy, RetainPermanent); ++ killprev(dpy, prev); + + XSync(dpy, False); ++ XCloseDisplay(dpy); + + return 0; +} diff --git a/st.suckless.org/patches/background_image/st-background-image-signal-reload-0.8.5.diff b/st.suckless.org/patches/background_image/st-background-image-signal-reload-0.8.5.diff @@ -1,51 +1,130 @@ -From 1317d64817460aee9321e29e5e31c072d59139c6 Mon Sep 17 00:00:00 2001 +From b56c9081dc4c62b7de5357cc73bc10a310f011b8 Mon Sep 17 00:00:00 2001 From: Matthias Schoth <mschoth@gmail.com> Date: Sun, 17 Apr 2022 04:01:59 +0200 Subject: [PATCH] Reload background image on USR1 signal. +Queue reload requests from the signal handler and service them from the +main loop. Xlib is not async-signal-safe, so calling it directly from the +handler can crash st or leak X resources when signals arrive while st is +drawing. --- - x.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) + x.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/x.c b/x.c -index fedef53..ac79ac7 100644 +index cab0058..7c9076c 100644 --- a/x.c +++ b/x.c -@@ -156,6 +156,7 @@ static int xicdestroy(XIC, XPointer, XPointer); +@@ -1,5 +1,6 @@ + /* See LICENSE for license details. */ + #include <errno.h> ++#include <fcntl.h> + #include <math.h> + #include <limits.h> + #include <locale.h> +@@ -157,6 +158,8 @@ static int xicdestroy(XIC, XPointer, XPointer); static void xinit(int, int); static void updatexy(void); static XImage *loadff(const char *); -+static void bgreload(); ++static void bgreload(int); ++static void bgreloadinit(void); static void bginit(); static void cresize(int, int); static void xresize(int, int); -@@ -1305,6 +1306,18 @@ loadff(const char *filename) +@@ -1319,6 +1322,46 @@ loadff(const char *filename) return xi; } ++static int bgreloadpipe[2] = {-1, -1}; ++ +/* -+ * reload background image on USR1 signal ++ * Xlib is not async-signal-safe, so just wake up the main loop and let it ++ * reload the image there. + */ -+void -+bgreload() ++static void ++bgreload(int sig) +{ -+ XFreeGC(xw.dpy, xw.bggc); -+ bginit(); -+ redraw(); -+ signal(SIGUSR1, bgreload); ++ char c = 0; ++ ++ (void)sig; ++ if (bgreloadpipe[1] != -1) ++ (void)write(bgreloadpipe[1], &c, 1); ++} ++ ++static void ++bgreloadinit(void) ++{ ++ struct sigaction sa; ++ int flags; ++ ++ if (pipe(bgreloadpipe) < 0) ++ die("pipe: %s\n", strerror(errno)); ++ ++ flags = fcntl(bgreloadpipe[0], F_GETFL); ++ fcntl(bgreloadpipe[0], F_SETFL, flags | O_NONBLOCK); ++ flags = fcntl(bgreloadpipe[1], F_GETFL); ++ fcntl(bgreloadpipe[1], F_SETFL, flags | O_NONBLOCK); ++ fcntl(bgreloadpipe[0], F_SETFD, FD_CLOEXEC); ++ fcntl(bgreloadpipe[1], F_SETFD, FD_CLOEXEC); ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_handler = bgreload; ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = SA_RESTART; ++ if (sigaction(SIGUSR1, &sa, NULL) < 0) ++ die("sigaction: %s\n", strerror(errno)); +} + /* * initialize background image */ -@@ -2193,6 +2206,7 @@ run: +@@ -2046,6 +2089,8 @@ run(void) + int w = win.w, h = win.h; + fd_set rfd; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; ++ int bgrfd = bgreloadpipe[0]; ++ char c; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; + +@@ -2072,6 +2117,7 @@ run(void) + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); ++ FD_SET(bgrfd, &rfd); + + if (XPending(xw.dpy)) + timeout = 0; /* existing events might not set xfd */ +@@ -2080,13 +2126,20 @@ run(void) + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); + tv = timeout >= 0 ? &seltv : NULL; + +- if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { ++ if (pselect(MAX(xfd, MAX(ttyfd, bgrfd))+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + clock_gettime(CLOCK_MONOTONIC, &now); + ++ if (FD_ISSET(bgrfd, &rfd)) { ++ while (read(bgrfd, &c, 1) > 0) ++ ; ++ bginit(); ++ redraw(); ++ } ++ + if (FD_ISSET(ttyfd, &rfd)) + ttyread(); + +@@ -2219,6 +2272,7 @@ run: + rows = MAX(rows, 1); tnew(cols, rows); xinit(cols, rows); ++ bgreloadinit(); bginit(); -+ signal(SIGUSR1, bgreload); xsetenv(); selinit(); - run(); -- -2.35.3 +2.55.0