sites

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

commit f1cb5288fde671367ba818f907d8287999613e1f
parent 39a23421c0017f93ced262bff70a97521c592302
Author: Abhishek Kumar <abhiiishekparmar@gmail.com>
Date:   Mon, 27 Oct 2025 14:40:59 +0530

[st][patches][changealpha]: fix alpha transparency overflow when increasing opacity

Fixes a bug where increasing opacity from certain alpha values
(e.g. 0.85 → 0.95 → 1.05) caused the terminal to become fully
transparent instead of opaque. The patch clamps the alpha value
between 0.1 and 1.0 to prevent overflow and compositor misbehavior.

2025-10-27

Diffstat:
Mst.suckless.org/patches/changealpha/index.md | 35+++++++++++++++++++++--------------
Ast.suckless.org/patches/changealpha/st-alpha-changealpha-20251027-0.9.3.diff | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/changealpha/st-changealpha-20251027-0.9.3.diff | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 307 insertions(+), 14 deletions(-)

diff --git a/st.suckless.org/patches/changealpha/index.md b/st.suckless.org/patches/changealpha/index.md @@ -4,12 +4,12 @@ A patch that allows for updating terminal transparency natively. ### Description -This patch is an extension to the [alpha](https://st.suckless.org/patches/alpha) patch, -which _must_ be applied prior. +This patch is an extension to the [alpha](https://st.suckless.org/patches/alpha) patch, +which _must_ be applied prior. ### Notes -* This patch assumes that the alpha variable is a float, which was only updated in alpha +* This patch assumes that the alpha variable is a float, which was only updated in alpha patch version 0.8.2 i.e., 0.8.2 is the minimum compatible version. * Don't forget to append "config.h" to the end of the rm command under the clean rule in Makefile if you are having issues running make install. @@ -18,25 +18,32 @@ Makefile if you are having issues running make install. Later versions of the default alpha patch provide a method of changing window opacity via the -A flag, however, with no method of querying the current alpha level, it is difficult -to write scripts which increment or decrement this value. It is typically possible to update -the opacity via your compositor, but not all compositors support this, and even if they do, -your setup is still less portable at the end of the day. The -[transset-df](https://aur.archlinux.org/packages/transset-df) package -located in the AUR is the closest I've come to changing opacity on a per-window basis, -however, it still requires writing a script and binding that script to some keys using a -keybinding manager of some sort. Not to mention, it's fatal flaw - you cannot increase the +to write scripts which increment or decrement this value. It is typically possible to update +the opacity via your compositor, but not all compositors support this, and even if they do, +your setup is still less portable at the end of the day. The +[transset-df](https://aur.archlinux.org/packages/transset-df) package +located in the AUR is the closest I've come to changing opacity on a per-window basis, +however, it still requires writing a script and binding that script to some keys using a +keybinding manager of some sort. Not to mention, it's fatal flaw - you cannot increase the opacity beyond the default value set with the alpha patch. +### Changelog +* **20251027-0.9.3**: Fixes a bug where increasing opacity from certain alpha values (e.g. 0.85 → 0.95 → 1.05) caused the terminal to become fully transparent instead of opaque. +The patch clamps alpha between 0.1 and 1.0 to prevent overflow and compositor misbehavior. + ### Download #### Patch: alpha (0.8.5) + changealpha -[st-alpha-changealpha-0.1.diff](st-alpha-changealpha-20230519-b44f2ad.diff) +* [st-alpha-changealpha-0.1.diff](st-alpha-changealpha-20230519-b44f2ad.diff) +* [st-alpha-changealpha-20251027-0.9.3.diff](st-alpha-changealpha-20251027-0.9.3.diff) #### Patch: changealpha -[st-changealpha-0.1.diff](st-changealpha-20230519-b44f2ad.diff) +* [st-changealpha-0.1.diff](st-changealpha-20230519-b44f2ad.diff) +* [st-changealpha-20251027-0.9.3.diff](st-changealpha-20251027-0.9.3.diff) -### Author +### Author -Neil Kingdom - <neil@neilkingdom.xyz> +* Neil Kingdom - <neil@neilkingdom.xyz> +* Abhishek Kumar - <abhiiishekparmar@gmail.com> (fixed transparency overflow issue) diff --git a/st.suckless.org/patches/changealpha/st-alpha-changealpha-20251027-0.9.3.diff b/st.suckless.org/patches/changealpha/st-alpha-changealpha-20251027-0.9.3.diff @@ -0,0 +1,200 @@ +diff --git a/st/config.def.h b/st_patched/config.def.h +index 91ab8ca..59fc2a9 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,6 +93,10 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* bg opacity */ ++float alpha = 0.8; ++float alpha_def; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -201,6 +205,9 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */ ++ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */ ++ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */ + }; + + /* +diff --git a/st/st.h b/st_patched/st.h +index fd3b0d8..cda8c13 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern float alpha, alpha_def; +diff --git a/st/config.mk b/st_patched/config.mk +index 1e306f8..47c615e 100644 +--- a/config.mk ++++ b/config.mk +@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config + INCS = -I$(X11INC) \ + `$(PKG_CONFIG) --cflags fontconfig` \ + `$(PKG_CONFIG) --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ ++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --libs fontconfig` \ + `$(PKG_CONFIG) --libs freetype2` + +diff --git a/st/x.c b/st_patched/x.c +index aa09997..3b05a55 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void chgalpha(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -105,6 +106,7 @@ typedef struct { + XSetWindowAttributes attrs; + int scr; + int isfixed; /* is fixed geometry? */ ++ int depth; /* bit depth */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ + } XWindow; +@@ -243,6 +245,7 @@ static char *usedfont = NULL; + static double usedfontsize = 0; + static double defaultfontsize = 0; + ++static char *opt_alpha = NULL; + static char *opt_class = NULL; + static char **opt_cmd = NULL; + static char *opt_embed = NULL; +@@ -752,7 +755,7 @@ xresize(int col, int row) + + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); + +@@ -812,6 +815,13 @@ xloadcols(void) + else + die("could not allocate color %d\n", i); + } ++ ++ /* set alpha value of bg color */ ++ if (opt_alpha) ++ alpha = strtof(opt_alpha, NULL); ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); ++ dc.col[defaultbg].pixel &= 0x00FFFFFF; ++ dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; + loaded = 1; + } + +@@ -1134,11 +1144,23 @@ xinit(int cols, int rows) + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; ++ XWindowAttributes attr; ++ XVisualInfo vis; + + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); +- xw.vis = XDefaultVisual(xw.dpy, xw.scr); ++ ++ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { ++ parent = XRootWindow(xw.dpy, xw.scr); ++ xw.depth = 32; ++ } else { ++ XGetWindowAttributes(xw.dpy, parent, &attr); ++ xw.depth = attr.depth; ++ } ++ ++ XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); ++ xw.vis = vis.visual; + + /* font */ + if (!FcInit()) +@@ -1147,8 +1169,11 @@ xinit(int cols, int rows) + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + ++ /* Backup default alpha value */ ++ alpha_def = alpha; ++ + /* colors */ +- xw.cmap = XDefaultColormap(xw.dpy, xw.scr); ++ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); + xloadcols(); + + /* adjust fixed window geometry */ +@@ -1168,19 +1193,15 @@ xinit(int cols, int rows) + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + xw.attrs.colormap = xw.cmap; + +- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) +- parent = XRootWindow(xw.dpy, xw.scr); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, +- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, ++ win.w, win.h, 0, xw.depth, InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); + + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; +- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, +- &gcvalues); +- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, +- DefaultDepth(xw.dpy, xw.scr)); ++ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); ++ dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + +@@ -1371,6 +1392,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + return numspecs; + } + ++void ++chgalpha(const Arg *arg) ++{ ++ if (arg->f == -1.0f && alpha >= 0.1f) ++ alpha -= 0.1f; ++ else if (arg->f == 1.0f && alpha < 1.0f) ++ alpha += 0.1f; ++ else if (arg->f == 0.0f) ++ alpha = alpha_def; ++ else ++ return; ++ ++ /* Clamp alpha so it never exceeds valid range */ ++ if (alpha < 0.1f) ++ alpha = 0.1f; ++ if (alpha > 1.0f) ++ alpha = 1.0f; ++ ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); ++ /* Required to remove artifacting from borderpx */ ++ cresize(0, 0); ++ redraw(); ++} ++ + void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + { +@@ -2038,6 +2077,9 @@ main(int argc, char *argv[]) + case 'a': + allowaltscreen = 0; + break; ++ case 'A': ++ opt_alpha = EARGF(usage()); ++ break; + case 'c': + opt_class = EARGF(usage()); + break; diff --git a/st.suckless.org/patches/changealpha/st-changealpha-20251027-0.9.3.diff b/st.suckless.org/patches/changealpha/st-changealpha-20251027-0.9.3.diff @@ -0,0 +1,86 @@ +diff --git a/config.def.h b/config.def.h +index 91ab8ca..8a06176 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -93,6 +93,9 @@ char *termname = "st-256color"; + */ + unsigned int tabspaces = 8; + ++/* Background opacity */ ++float alpha_def; ++ + /* Terminal colors (16 first used in escape sequence) */ + static const char *colorname[] = { + /* 8 normal colors */ +@@ -201,6 +204,9 @@ static Shortcut shortcuts[] = { + { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { ShiftMask, XK_Insert, selpaste, {.i = 0} }, + { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, ++ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */ ++ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */ ++ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */ + }; + + /* +diff --git a/st.h b/st.h +index fd3b0d8..3bb587e 100644 +--- a/st.h ++++ b/st.h +@@ -124,3 +124,4 @@ extern unsigned int tabspaces; + extern unsigned int defaultfg; + extern unsigned int defaultbg; + extern unsigned int defaultcs; ++extern float alpha_def; +diff --git a/x.c b/x.c +index aa09997..f8c8c1a 100644 +--- a/x.c ++++ b/x.c +@@ -59,6 +59,7 @@ static void zoom(const Arg *); + static void zoomabs(const Arg *); + static void zoomreset(const Arg *); + static void ttysend(const Arg *); ++static void chgalpha(const Arg *); + + /* config.h for applying patches and the configuration. */ + #include "config.h" +@@ -1147,6 +1148,9 @@ xinit(int cols, int rows) + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + ++ /* Backup default alpha value */ ++ alpha_def = alpha; ++ + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); +@@ -1371,6 +1375,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x + return numspecs; + } + ++void ++chgalpha(const Arg *arg) ++{ ++ if (arg->f == -1.0f && alpha >= 0.1f) ++ alpha -= 0.1f; ++ else if (arg->f == 1.0f && alpha < 1.0f) ++ alpha += 0.1f; ++ else if (arg->f == 0.0f) ++ alpha = alpha_def; ++ else ++ return; ++ ++ /* Clamp alpha so it never exceeds valid range */ ++ if (alpha < 0.1f) ++ alpha = 0.1f; ++ if (alpha > 1.0f) ++ alpha = 1.0f; ++ ++ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha); ++ /* Required to remove artifacting from borderpx */ ++ cresize(0, 0); ++ redraw(); ++} ++ + void + xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) + {