Skip to content

The tooltip mute reaches as far as the grab, and no further - #208

Merged
ghackett merged 1 commit into
mainfrom
tooltipmute-scoped-to-window-group
Aug 8, 2026
Merged

The tooltip mute reaches as far as the grab, and no further#208
ghackett merged 1 commit into
mainfrom
tooltipmute-scoped-to-window-group

Conversation

@ghackett

@ghackett ghackett commented Aug 8, 2026

Copy link
Copy Markdown
Member

Follow-up to 206, which merged before its review was addressed. The review
flagged the app-wide sweep in tooltipmute._mute() as a cross-window bug:
opening a menu in one window silences tooltips in another, "fully interactive"
window.

The premise doesn't hold — a menu in one Collins window really does shadow
the next one.
gtk_grab_add registers the grab on the window group, not
the window, and documents itself as blocking "interaction with other widgets in
the same application". gtk_main_do_event then looks the current grab up by
the group of whatever window the event lands in:

window_group = gtk_main_get_window_group (target_widget);
grab_widget = gtk_window_group_get_current_grab (window_group);
if (!grab_widget || (… gtk_widget_is_ancestor (target_widget, grab_widget)) || …)
  grab_widget = target_widget;
…
handled_event = gtk_propagate_event (grab_widget, event);

Collins never creates a GtkWindowGroup, so all its windows sit in the default
one: with a menu open in window A, a click on a control in window B is routed
to the popover and dismisses the menu instead. A control that can't be clicked
shouldn't be explaining itself, so muting it was right.

What was actually wrong is that none of this was written down, and the code
took the app-wide shortcut rather than saying what it meant.
So this scopes
the mute to the popover's window group — the same set today, and the right set
if a window ever gets a group of its own:

  • _open/_muted are keyed by Gtk.WindowGroup instead of being process-global.
  • The sweep skips toplevels in another group.
  • _on_query mutes within the queried widget's group only, and a widget with
    no root is left alone (it can't show a tooltip anyway).
  • Each group unmutes when its last menu closes, instead of waiting for every
    other window's menus.

Also documents the second review note: a menu opening over a menu re-sweeps its
group on purpose (the new menu is a fresh subtree to spare, and the first sweep
leaves so little armed that the walk is all it costs), and a GtkPopoverMenu's
submenus don't come through that path at all — they're pages of one popover.

Verification

Same headless probes as 206, all still passing (context menu mutes all 66
tooltip-bearing widgets and restores all of them; a popover's own tooltips
survive; a widget created mid-menu is muted on first query; a GtkMenuButton's
popover behaves the same), plus a new two-window probe:

check result
two windows share the default group pass
a menu in A mutes B (same group, so B is shadowed too) pass — 0 of 47 left armed
B restored when A's menu closes pass
after B is given its own GtkWindowGroup, a menu in A leaves B alone pass — 47 of 47 still armed
A itself still muted in that case pass

No screenshots: nothing about the rendered UI changes here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FD7QTvXtBfAUDCkLa3eqZe

Review follow-up to 206: the sweep walked every toplevel in the process, on
the reasoning that a menu shadows the whole app. That reasoning is right for
Collins but it was never spelled out, and it was spelled out nowhere in the
code — so scope it explicitly to the popover's window group, which is exactly
what its grab covers. gtk_grab_add registers the grab on the group, and
gtk_main_do_event looks the current grab up by the group of whatever window an
event lands in, then routes the event to the grab widget. Collins puts every
window in the default group, so today this mutes the same set as before; a
window in a group of its own stays interactive, and now keeps its tooltips.

Also says why a menu opening over a menu re-sweeps: the second menu is a fresh
subtree to spare, and the first sweep leaves so little armed that the walk is
all it costs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FD7QTvXtBfAUDCkLa3eqZe
@ghackett
ghackett marked this pull request as ready for review August 8, 2026 17:12
@ghackett
ghackett merged commit 2c926cf into main Aug 8, 2026
2 checks passed
@ghackett
ghackett deleted the tooltipmute-scoped-to-window-group branch August 8, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant