GNOME Shell crashes when a resize edge is touched with a finger #7

Closed
opened 2026-10-13 02:31:59 +00:00 by asxpi · 0 comments

On Linux under GNOME (Wayland, mutter 50.2), touching the window's resize edges with a finger can crash GNOME Shell, which ends the whole session. It happened four times on 2026-10-13 on a touchscreen laptop, always at the same address.

What happens

With the client-side title bar, the invisible resize edges (aim-window-frame, ui/src/views/window-controls.ts) call startResizeDragging on mousedown. WebKitGTK sends a mousedown for a touch too, so a finger on an edge makes Tauri/GTK send xdg_toplevel.resize with the touch's serial. If mutter has already cancelled that touch, it dereferences NULL:

#0 touch_can_grab_surface               (mutter src/wayland/meta-wayland-touch.c)
#1 meta_wayland_touch_find_grab_sequence
#2 meta_wayland_seat_get_grab_info
#3 xdg_toplevel_resize
kernel: .gnome-shell-wr[69083]: segfault at 0 ... error 4 in libmutter-18.so.0.0.0[1dcaa3,...]

meta_wayland_touch_cancel() clears focus_surface on every active touch but keeps each touch's serial until the finger lifts, and touch_can_grab_surface() reads touch_info->focus_surface->surface without a check. This is a mutter bug (any client can trigger it; mutter main still has the same code), but our resize edges are what set it off here.

Fix on our side

Have the edges react to pointerdown and skip pointerType === 'touch': a 6px edge is no target for a finger anyway, and mouse resizing stays as it is. A local change does this, with a case in ui/test/window-frame.test.ts (41/41 pass, tsc clean):

@pointerdown=${(e: PointerEvent) => {
    if (e.pointerType === 'touch' || e.button !== 0) return;
    e.preventDefault();
    e.stopPropagation();
    void frame.startResizeDragging(dir).catch(() => undefined);
}}

Moving the window by dragging the title bar with a finger (ui/src/views/window-drag.ts, startDragging → xdg_toplevel.move) goes through the same unchecked mutter code. It was not seen to crash and is worth keeping, but it may need the same guard if it does.

Upstream

The mutter fix is a NULL check in touch_can_grab_surface(); it is to be sent to GNOME/mutter. Until then, NixOS users can carry it as a patch on mutter.

On Linux under GNOME (Wayland, mutter 50.2), touching the window's resize edges with a finger can crash GNOME Shell, which ends the whole session. It happened four times on 2026-10-13 on a touchscreen laptop, always at the same address. ## What happens With the client-side title bar, the invisible resize edges (`aim-window-frame`, `ui/src/views/window-controls.ts`) call `startResizeDragging` on `mousedown`. WebKitGTK sends a `mousedown` for a touch too, so a finger on an edge makes Tauri/GTK send `xdg_toplevel.resize` with the touch's serial. If mutter has already cancelled that touch, it dereferences NULL: ``` #0 touch_can_grab_surface (mutter src/wayland/meta-wayland-touch.c) #1 meta_wayland_touch_find_grab_sequence #2 meta_wayland_seat_get_grab_info #3 xdg_toplevel_resize ``` ``` kernel: .gnome-shell-wr[69083]: segfault at 0 ... error 4 in libmutter-18.so.0.0.0[1dcaa3,...] ``` `meta_wayland_touch_cancel()` clears `focus_surface` on every active touch but keeps each touch's serial until the finger lifts, and `touch_can_grab_surface()` reads `touch_info->focus_surface->surface` without a check. This is a mutter bug (any client can trigger it; mutter `main` still has the same code), but our resize edges are what set it off here. ## Fix on our side Have the edges react to `pointerdown` and skip `pointerType === 'touch'`: a 6px edge is no target for a finger anyway, and mouse resizing stays as it is. A local change does this, with a case in `ui/test/window-frame.test.ts` (41/41 pass, `tsc` clean): ```ts @pointerdown=${(e: PointerEvent) => { if (e.pointerType === 'touch' || e.button !== 0) return; e.preventDefault(); e.stopPropagation(); void frame.startResizeDragging(dir).catch(() => undefined); }} ``` Moving the window by dragging the title bar with a finger (`ui/src/views/window-drag.ts`, `startDragging` → `xdg_toplevel.move`) goes through the same unchecked mutter code. It was not seen to crash and is worth keeping, but it may need the same guard if it does. ## Upstream The mutter fix is a NULL check in `touch_can_grab_surface()`; it is to be sent to GNOME/mutter. Until then, NixOS users can carry it as a patch on `mutter`.
ann closed this issue 2026-10-15 18:00:52 +00:00
ann referenced this issue from a commit 2026-10-27 11:52:18 +00:00
Android lock fixes from the final audit of 2026-10-27 (findings 1, 3, 4, 7, 8, 9, 10, 11): every lock now runs on DeviceLock's one worker and looks at the store itself (storage info) when its turn comes, so a screen-off heard while the silent reopen is still opening the tier closes it again instead of being dropped (H1), and a reopen or a fingerprint open that ends with the phone already off or locked is closed again at once (DeviceLock.opened, called from MainActivity.presence after Relock.keep); behind a secure lock an open split store closes at every lock whether or not a copy of K2 is held, the copy deciding only whether the unlock is silent, and with no copy the page is told __anotherDeviceLocked('fingerprint') and the gate says why it asks (M3, new string in en ru uk et es); a close libtacky holds back for a call or a transfer (close_main closed 0) sets DeviceLock.closeHeld, the bridge's deviceClosePending(status) makes the page take that unlocked store as call (shellStatus in store.begin and recheck), so a fresh window after a swipe during a call gets the fingerprint, and open-main over the held close releases K2 through the prompt and calls the close off, or opens the tier with it where the close went meanwhile (M4); the page publishes its drafts and answers deviceLockFlushed after a request round trip before close_main goes (at most a second, #11); the gate offers the fingerprint after RELOCK_WAIT_MS (15 s) of a reopen that never comes (#10); Relock.take sleeps for its retry outside the object's lock (#9); EnrolmentProbe counts an unexpected Keystore exception on a made probe as a change, fail closed (#8); the headers of DeviceLock, Relock and docs/push.md now say K2 passes through JVM strings that are released, not zeroed (#7, K2 over JNI as bytes left for later). Ringing still counts as busy in libtacky's MainTierBusy (libtacky's, not changed here). Tests: RelockTest 8 new (screen off during the reopen with the keyguard locked and within the lock delay, both failing on the old code; an open ending behind the lock; a held close keeping a fresh window at the fingerprint and called off by the prompt, or opened by it where it went; the close waiting for the page's drafts; a take's retry not holding drop), DeviceLockTest and WatchesTest updated for the close without a copy, KeystoreSealersTest for the fail-closed probe; device-lock.test.ts and storage-gate.test.ts 6 new; JVM free 485, gms 488, all passing; make check STRICT=1 clean; make test-ui 380 files, 4168 passed, 8 skipped; make test-shell ok.
ann referenced this issue from a commit 2026-10-27 15:08:57 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
another-im/anotherim-js#7
No description provided.