From 6c99d2f9d1e249cd8e56752468c6f8b53181d2a6 Mon Sep 17 00:00:00 2001 From: Ken Sanislo Date: Mon, 11 May 2026 00:56:15 -0700 Subject: [PATCH] PerKey dialog: size window from measured natural size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dialog used hardcoded offsets to compute its target size from the canvas's size_request: target_w = canvas_w + 32 # 8 wrapper border * 2 + ~16 scrollbar slack target_h = canvas_h + 80 # 8 wrapper border * 2 + 50 toolbar + slack Two problems with that: 1. The "+32" only covered the canvas's width plus borders, not the toolbar's width. Small layouts (e.g. an 8-LED mouse: canvas ~172px) produced a window narrower than the toolbar wanted (~261px with the icon buttons + palette + color picker + unset toggle), causing toolbar overflow / clipping. 2. The "+80" assumed a fixed toolbar height and scrollbar slack — wrong on themes with chunkier buttons or different scrollbar metrics, and brittle to any future toolbar additions. Replace with `wrapper.get_preferred_size()`. GTK already aggregates the canvas's size_request through ScrolledWindow + the editor VBox + the wrapper's border into a natural size that accounts for every contribution, including the toolbar's width. Drop the now-unused `canvas_size()` shim from PerKeyEditor. --- lib/solaar/ui/perkey/dialog.py | 17 ++++++++--------- lib/solaar/ui/perkey/editor.py | 6 ------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/lib/solaar/ui/perkey/dialog.py b/lib/solaar/ui/perkey/dialog.py index b58aaf47..21cb1f27 100644 --- a/lib/solaar/ui/perkey/dialog.py +++ b/lib/solaar/ui/perkey/dialog.py @@ -69,15 +69,14 @@ class PerKeyEditorDialog: self._wrapper.pack_start(self._editor, True, True, 0) self._wrapper.show_all() self._window.set_title(_("Per-key Lighting") + " — " + sink.title) - # Resize to fit canvas + toolbar. ScrolledWindow's *minimum* is tiny - # (one row's worth) regardless of propagate_natural_size, so we have - # to compute the target ourselves from the canvas's size_request. - canvas_w, canvas_h = self._editor.canvas_size() - if canvas_w > 0 and canvas_h > 0: - # Toolbar ~50px, wrapper border 8px each side, scrollbar slack ~4. - target_w = canvas_w + 32 - target_h = canvas_h + 80 - self._window.resize(target_w, target_h) + # Ask GTK what the wrapper actually wants to be — the canvas's + # size_request propagates up through ScrolledWindow + editor VBox + # (toolbar + scrolled canvas) + the wrapper's border, so the + # natural size already accounts for every layout contribution + # rather than hardcoding "toolbar ~50, border 8 each side". + _min, nat = self._wrapper.get_preferred_size() + if nat.width > 0 and nat.height > 0: + self._window.resize(nat.width, nat.height) self._window.present() diff --git a/lib/solaar/ui/perkey/editor.py b/lib/solaar/ui/perkey/editor.py index 2de7276d..20005717 100644 --- a/lib/solaar/ui/perkey/editor.py +++ b/lib/solaar/ui/perkey/editor.py @@ -156,12 +156,6 @@ class PerKeyEditor(Gtk.Box): except Exception as e: logger.debug("palette shutdown failed: %s", e) - def canvas_size(self) -> tuple[int, int]: - """Return the canvas's pixel size_request — what the dialog should - size its content area to so the layout fits without scrollbars. - """ - return self._canvas.get_size_request() - def _refresh_layout(self) -> None: if self._layout is None: # No registered layout: lay out all reported zones as a flat strip.