From 121235db5ca23e53e0dad3a402c521dc7a940fbc Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 17 Sep 2026 08:07:00 +0200 Subject: feat(icons): read the icon theme from gsettings The icon theme name was hardcoded in three places (bin/wb-icon, modules/extras/taskbar.jsonc and install.sh), so switching themes in the appearance drawer was silently reverted as far as this bar was concerned. wb-icon now reads org.gnome.desktop.interface icon-theme and gains two modes for install.sh: --path NAME prints one icon's absolute path, --theme prints the resolved theme name. Icons are resolved per name rather than by substituting a directory prefix, because themes disagree about both subdirectory and file extension: the Suru themes keep web-browser at categories/22/*.svg, elementary-xfce at apps/22/*.png. Only a real GTK lookup knows the path. styles/modules.css therefore carries @ICON:name@ placeholders and modules/extras/taskbar.jsonc carries @ICON_THEME@, both filled at install time. taskbar.jsonc is generated rather than symlinked for that reason, and install.sh removes the old symlink first so the redirect cannot overwrite the committed source. A theme missing one of the twenty names fails the install at the --selftest step rather than drawing empty pills. Co-Authored-By: Claude Opus 5 --- bin/wb-icon | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) (limited to 'bin/wb-icon') diff --git a/bin/wb-icon b/bin/wb-icon index 9e011b9..1d76369 100755 --- a/bin/wb-icon +++ b/bin/wb-icon @@ -10,6 +10,7 @@ # # wb-icon volume # reads wpctl, prints the matching icon # wb-icon mic +# wb-icon --path NAME # absolute path of one icon, for install.sh # wb-icon --selftest # every name this bar asks for must resolve # # Icons keep their own colours: this desktop's icon theme draws them with @@ -24,9 +25,29 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa: E402 (must follow require_version) -# The icon theme to draw from. Kept in one place because changing it is a -# single edit, and because --selftest needs the same value the modules use. -THEME = "Material-Black-Plum-Suru" +# The icon theme to draw from: whatever the desktop is set to. The appearance +# drawer switches it through gsettings, so reading that key is what keeps this +# bar following a switch instead of silently pointing at the old theme. +# +# The fallback only matters when gsettings is unreadable; GTK falls back to +# hicolor on its own if the named theme is missing. +FALLBACK_THEME = "Adwaita" + + +def icon_theme(): + """The desktop's icon theme name, per gsettings.""" + try: + out = subprocess.run( + ["gsettings", "get", "org.gnome.desktop.interface", "icon-theme"], + capture_output=True, text=True, timeout=2, + ).stdout.strip() + except (OSError, subprocess.SubprocessError): + return FALLBACK_THEME + # gsettings quotes its answer: 'Material-Black-Plum-Suru' + return out.strip("'\"") or FALLBACK_THEME + + +THEME = icon_theme() SIZE = 22 @@ -47,7 +68,13 @@ ICONS = { def lookup(name): - """Absolute path of an icon in THEME, or None.""" + """Absolute path of an icon in THEME, or None. + + GTK resolves the theme's own layout, so this works across icon themes + that disagree about subdirectory and file extension: the Suru themes keep + web-browser under categories/22/*.svg, elementary-xfce under apps/22/*.png. + Nothing outside this function may assume a path shape. + """ theme = Gtk.IconTheme.new() theme.set_custom_theme(THEME) info = theme.lookup_icon(name, SIZE, 0) @@ -138,7 +165,8 @@ def selftest(): def main(argv): if len(argv) < 2 or argv[1] in ("-h", "--help"): - print(__doc__ or "usage: wb-icon [state]") + print(__doc__ or + "usage: wb-icon ") return 0 what = argv[1] @@ -146,6 +174,25 @@ def main(argv): if what == "--selftest": return selftest() + # install.sh bakes icon paths into the generated stylesheet, because CSS + # cannot look an icon up by name. It asks here so that the theme is + # resolved in exactly one place. + if what == "--path": + if len(argv) < 3: + print("wb-icon: --path needs an icon name", file=sys.stderr) + return 2 + path = lookup(argv[2]) + if not path: + print(f"wb-icon: no icon named {argv[2]!r} in {THEME}", + file=sys.stderr) + return 1 + print(path) + return 0 + + if what == "--theme": + print(THEME) + return 0 + if what == "volume": pct, muted = wpctl("@DEFAULT_AUDIO_SINK@") if pct is None: -- cgit v1.2.3