PerKeyEditor: rebuild tool icons on GTK theme change

Tool icon pixbufs are baked at construction time using the button's
current style context foreground color. Without this, switching the
desktop theme (e.g. light <-> dark) at runtime leaves the editor's
icons stuck in the previous color while the rest of the UI updates.

Subscribe to Gtk.Settings notify::gtk-theme-name and
notify::gtk-application-prefer-dark-theme; on either, replace each
themed button's child Gtk.Image with a freshly-recolored one.
Disconnect both signals from PerKeyEditor.shutdown so the editor
doesn't leak handlers across openings.
This commit is contained in:
Ken Sanislo 2026-05-11 00:28:26 -07:00 committed by Peter F. Patel-Schneider
parent cf9a88bcaf
commit 1210d32b93
1 changed files with 30 additions and 0 deletions

View File

@ -130,6 +130,9 @@ class PerKeyEditor(Gtk.Box):
# toolbar row
toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
self._tool_buttons: dict[str, Gtk.RadioButton] = {}
# Track which buttons display a themed icon, so we can re-render them
# when the active GTK theme switches (light <-> dark, theme name).
self._themed_icon_buttons: dict[Gtk.RadioButton, str] = {}
self._gradient_swatch: GradientSwatch | None = None
first: Gtk.RadioButton | None = None
supported = layout.supported_tools if layout else ("single", "rect", "bucket", "gradient")
@ -150,6 +153,7 @@ class PerKeyEditor(Gtk.Box):
btn.add(image)
btn.set_tooltip_text(tip or label)
btn.get_accessible().set_name(label)
self._themed_icon_buttons[btn] = icon_name
else:
btn.set_label(label)
btn.set_tooltip_text(tip)
@ -159,6 +163,14 @@ class PerKeyEditor(Gtk.Box):
toolbar.pack_start(btn, False, False, 0)
self._tool_buttons[name] = btn
# Re-render themed icons when the GTK theme changes at runtime.
self._theme_signal_handlers: list[tuple[object, int]] = []
if self._themed_icon_buttons:
settings = Gtk.Settings.get_default()
for prop in ("notify::gtk-theme-name", "notify::gtk-application-prefer-dark-theme"):
hid = settings.connect(prop, self._on_gtk_theme_changed)
self._theme_signal_handlers.append((settings, hid))
initial_active, initial_previous = 0xFF0000, 0xFF0000
try:
persisted = sink.palette_state()
@ -209,6 +221,24 @@ class PerKeyEditor(Gtk.Box):
except Exception as e:
logger.debug("perkey sink unsubscribe failed: %s", e)
self._unsubscribe = None
for obj, hid in self._theme_signal_handlers:
try:
obj.disconnect(hid)
except Exception as e:
logger.debug("theme signal disconnect failed: %s", e)
self._theme_signal_handlers = []
def _on_gtk_theme_changed(self, _settings, _pspec) -> None:
"""Rebuild themed tool icons so they match the new theme's foreground."""
for btn, icon_name in self._themed_icon_buttons.items():
old = btn.get_child()
new_image = _tool_icon_image(icon_name, btn)
if new_image is None:
continue
if old is not None:
btn.remove(old)
btn.add(new_image)
new_image.show()
def canvas_size(self) -> tuple[int, int]:
"""Return the canvas's pixel size_request — what the dialog should