Skip to content

fix: avoid pointer grab stuck on button press (Wayland)#1428

Open
KonTy wants to merge 1 commit into
elkowar:masterfrom
smpl-os:fix/button-pointer-grab
Open

fix: avoid pointer grab stuck on button press (Wayland)#1428
KonTy wants to merge 1 commit into
elkowar:masterfrom
smpl-os:fix/button-pointer-grab

Conversation

@KonTy

@KonTy KonTy commented Mar 21, 2026

Copy link
Copy Markdown

Problem

When a button's onclick command opens a window (e.g. a launcher, popup, or overlay) that steals Wayland focus before the button_release_event arrives back at the EWW bar, GTK's internal pointer grab is never released. This causes the entire bar to get "stuck":

  • Hover highlighting stops working on all other buttons
  • Clicks either do nothing or re-trigger the originally grabbed button
  • The user must wiggle the mouse to break free

This affects every EWW user on Hyprland/Wayland whose bar buttons open external windows. The community workaround has been adding sleep 0.1 before commands.

Root Cause

emit_activate() on button_press_event (line 542 of widget_definitions.rs) triggers GTK's built-in Button activation, which includes an implicit pointer grab via GDK seat grab. If the button_release_event is intercepted by another layer-shell surface that opens before the release arrives, the grab is never freed.

As @Rayzeq analyzed in #1022:

  1. GTK button grabs the pointer on press
  2. The onclick command opens a window that steals focus
  3. The release event goes to the new window, not the bar
  4. GTK never receives the release → grab never freed → all events redirect to the stuck button

Fix

Replace emit_activate() with manual :active CSS state management (the same pattern eventbox already uses):

  • On press: Set StateFlags::ACTIVE for visual feedback (preserves the button animation)
  • On release: Clear ACTIVE and run the command (unchanged behavior)
  • On grab_broken: Clear ACTIVE as a safety net if the grab is stolen by another surface

This preserves the press/release visual animation while eliminating the pointer grab that causes the stuck state. No user-facing API changes.

Testing

  • Compiled and verified on Arch Linux with Hyprland
  • The fix is a single-file change (~18 lines added, 5 removed) in widget_definitions.rs
  • Bar buttons that launch external windows (launchers, notification centers, calendar overlays) no longer cause the stuck state

Fixes #1008
Fixes #1022

When a button's onclick command opens a window (e.g. a launcher, popup,
or overlay) that steals Wayland focus before the button_release_event
arrives back at the EWW bar, GTK's internal pointer grab is never
released. This causes the entire bar to get 'stuck': hover highlighting
stops working on all other buttons, and clicks either do nothing or
re-trigger the originally grabbed button. The user must wiggle the mouse
to break free.

Root cause: emit_activate() on button_press_event triggers GTK's
built-in Button activation, which includes an implicit pointer grab
(GDK seat grab). If the release event is intercepted by another
layer-shell surface, the grab is never freed.

Fix: Replace emit_activate() with manual :active CSS state management.
On press, set StateFlags::ACTIVE for visual feedback. On release, clear
it and run the command. Also handle grab_broken_event as a safety net
to clear the :active state if the grab is stolen.

This preserves the button press/release animation while eliminating the
pointer grab that causes the stuck state.

Fixes: elkowar#1008
Fixes: elkowar#1022
KonTy pushed a commit to smpl-os/smplos that referenced this pull request Mar 21, 2026
- Revert 'sleep 0.05 &&' from all 9 tray button onclick handlers
  (no longer needed with patched EWW binary that avoids emit_activate)
- Add migration to auto-clean sleep workarounds on existing installs
- Fix smplos-refresh-config to search src/shared/ for eww configs
- Patched EWW binary (eww-0.6.0-2) in build/prebuilt/ for ISO builds

Root cause: GTK button_press_event -> emit_activate() grabs the pointer;
if onclick spawns a window that steals Wayland focus before button_release,
the grab is never freed. Fix: replace emit_activate() with manual :active
CSS state management (StateFlags::ACTIVE).

PR: elkowar/eww#1428
Fork: https://github.com/smpl-os/eww (branch: fix/button-pointer-grab)
Rellotscrewdriver added a commit to Rellotscrewdriver/CustomEww that referenced this pull request May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant