sites

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

commit 36cf773e954d3abbd244db5dcb1734f73bb3ce16
parent 0825ea76deded03e123bb6dccb304ecbede0e529
Author: Matthias Schoth <mschoth@gmail.com>
Date:   Tue, 18 Aug 2026 19:48:40 +0200

[st][patches][background-images] Defer position sync to the draw path

The pseudotransparency feature blits the root window's pixmap into the
terminal, anchored to the window's screen position. That origin is only
ever consumed by xclear() at paint time, yet updatexy() (causing a synchronous
X server round-trip) was previously invoked from scattered event handlers
(resize, propnotify, bginit, run). Now we track whether the window may have
moved (posdirty) and resolve the origin lazily, exactly once, on the first
draw after a move. The authoritative position is fetched at draw time, so
coalesced or redundant events are always resolved to the latest true position.

A same-size ConfigureNotify (a pure move) repaints only when posdirty is set,
via tfulldirt() rather than redraw(). tfulldirt() marks all rows dirty and lets
the run loop's single draw() do the repaint which means no synchronous draw
inside the event handler, and no double draw.

As a result steady-state frames incur zero X round-trips and a move now costs
exactly one round-trip on the first frame after it. A burst of ConfigureNotify
events (drag across monitors, quick tiling changes) costs one round-trip and
one coalesced repaint in total instead of one synchronous full-screen repaint
per event.

Diffstat:
Mst.suckless.org/patches/background_image/st-background-image-0.9.3.diff | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 67 insertions(+), 33 deletions(-)

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 5f070227058901afd7525ffe6363c93faf163ef0 Mon Sep 17 00:00:00 2001 +From b43b4842d62d800da712ef7d6244967daa4ff096 Mon Sep 17 00:00:00 2001 From: Matthias Schoth <mschoth@gmail.com> -Date: Fri, 31 Jul 2026 23:50:51 +0200 +Date: Tue, 18 Aug 2026 19:32:18 +0200 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 @@ -19,9 +19,11 @@ property. It is not built by default; compile separately with: cc -o stbg stbg.c -lX11 --- config.def.h | 6 +++ - stbg.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ - x.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++---- - 3 files changed, 246 insertions(+), 10 deletions(-) + st.c | 2 +- + st.h | 1 + + stbg.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ + x.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++---- + 5 files changed, 248 insertions(+), 10 deletions(-) create mode 100644 stbg.c diff --git a/config.def.h b/config.def.h @@ -41,6 +43,31 @@ index 2cd740a..3d98c87 100644 /* * What program is execed by st depends of these precedence rules: * 1: program passed with -e +diff --git a/st.c b/st.c +index 8e57991..2663816 100644 +--- a/st.c ++++ b/st.c +@@ -194,7 +194,7 @@ static void tsetscroll(int, int); + static void tswapscreen(void); + static void tsetmode(int, int, const int *, int); + static int twrite(const char *, int, int); +-static void tfulldirt(void); ++void tfulldirt(void); + static void tcontrolcode(uchar ); + static void tdectest(char ); + static void tdefutf8(char); +diff --git a/st.h b/st.h +index fd3b0d8..a716a73 100644 +--- a/st.h ++++ b/st.h +@@ -89,6 +89,7 @@ void toggleprinter(const Arg *); + int tattrset(int); + void tnew(int, int); + void tresize(int, int); ++void tfulldirt(void); + void tsetdirtattr(int); + void ttyhangup(void); + int ttynew(const char *, char *, const char *, char **); diff --git a/stbg.c b/stbg.c new file mode 100644 index 0000000..80bc4cf @@ -170,7 +197,7 @@ index 0000000..80bc4cf + return 0; +} diff --git a/x.c b/x.c -index d73152b..c0ec757 100644 +index d73152b..bee9d35 100644 --- a/x.c +++ b/x.c @@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec; @@ -201,7 +228,15 @@ index d73152b..c0ec757 100644 static void cresize(int, int); static void xresize(int, int); static void xhints(void); -@@ -515,6 +522,18 @@ propnotify(XEvent *e) +@@ -220,6 +227,7 @@ static DC dc; + static XWindow xw; + static XSelection xsel; + static TermWindow win; ++static int posdirty = 1; /* window may have moved; re-sync tile origin */ + + /* Font Ring Cache */ + enum { +@@ -515,6 +523,17 @@ propnotify(XEvent *e) xpev->atom == clipboard)) { selnotify(e); } @@ -214,7 +249,6 @@ index d73152b..c0ec757 100644 + + if (pseudotransparency && + e->xproperty.atom == xw.netwmstate_atom) { -+ updatexy(); + redraw(); + } } @@ -257,7 +291,7 @@ index d73152b..c0ec757 100644 } void -@@ -1242,6 +1264,78 @@ xinit(int cols, int rows) +@@ -1242,6 +1264,77 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } @@ -323,7 +357,6 @@ index d73152b..c0ec757 100644 + } + + if (pseudotransparency) { -+ updatexy(); + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + } @@ -336,7 +369,7 @@ index d73152b..c0ec757 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -@@ -1482,7 +1576,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i +@@ -1482,7 +1575,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. */ @@ -348,37 +381,38 @@ index d73152b..c0ec757 100644 /* Set the clip region because Xft is sometimes dirty. */ r.x = 0; -@@ -1914,9 +2011,17 @@ cmessage(XEvent *e) +@@ -1651,6 +1747,12 @@ xsettitle(char *p) + int + xstartdraw(void) + { ++ if (pseudotransparency && IS_SET(MODE_VISIBLE)) { ++ if (posdirty) { ++ updatexy(); ++ posdirty = 0; ++ } ++ } + return IS_SET(MODE_VISIBLE); + } + +@@ -1914,9 +2016,15 @@ cmessage(XEvent *e) void resize(XEvent *e) { - if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) - return; -- -+ if (pseudotransparency) { -+ if (e->xconfigure.width == win.w && -+ e->xconfigure.height == win.h && -+ e->xconfigure.x == win.x && e->xconfigure.y == win.y) -+ return; -+ updatexy(); -+ } else { -+ if (e->xconfigure.width == win.w && -+ e->xconfigure.height == win.h) -+ return; ++ if (pseudotransparency && ++ (e->xconfigure.x != win.x || e->xconfigure.y != win.y)) ++ posdirty = 1; + ++ if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) { ++ if (pseudotransparency && posdirty) ++ tfulldirt(); ++ return; + } cresize(e->xconfigure.width, e->xconfigure.height); } -@@ -1947,6 +2052,8 @@ run(void) - } while (ev.type != MapNotify); - - ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); -+ if (pseudotransparency) -+ updatexy(); - cresize(w, h); - - for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { -@@ -2100,6 +2207,7 @@ run: +@@ -2100,6 +2208,7 @@ run: rows = MAX(rows, 1); tnew(cols, rows); xinit(cols, rows);