Skip to content

fix(compositor): Escape cancels a client drag, as Mutter's drag grab does (#655) - #675

Merged
hanthor merged 1 commit into
mainfrom
fix/escape-cancels-client-drag
Oct 15, 2026
Merged

hanthor merged 1 commit into
mainfrom
fix/escape-cancels-client-drag

Conversation

@hanthor

@hanthor hanthor commented Oct 15, 2026

Copy link
Copy Markdown
Member

Fixes #655 (G-GRID-DRAG-CANCEL: "cancelled folder drag changed the saved layout").

Stacked on #674. This branch's base is fix/grid-drag-page-flakes, whose proof helpers (a11y_until) and grid fixes it uses. Merge #674 first; GitHub then retargets this PR to main.

Failure history

The "changed the saved layout" mode on main-equivalent grid code, last 150 ci runs:

#655 counted about 5 in 20 runs earlier on 10-14, mixed with other failures. The remaining G-GRID-DRAG-CANCEL failures in the window ("GTK drag cleanup did not restore arrow before release", "native cancellation evidence…", 6 runs) came from Codex branches that carry #654's rewritten cancel proof, not main's.

Root cause

Runtime::on_manager_input (crates/compositor/src/runtime.rs:1230-1241 on main) consumes Escape to close the overview but leaves the shell's Wayland drag running. The proof sends key Escape and then mouseup. The overview close travels the control socket to the shell, which hides the grid. The release travels the DnD grab to the still-focused grid surface as wl_data_device.drop. When the drop reaches GTK first, the tile under the pointer takes it: on_drop → reorder → GridReflow::commit (crates/shell-gtk/src/overview.rs:642-653), which saves the reorder that the hover reflow had only previewed. In run 38518164407's nested.log the hover timer fires, Escape closes the overview, and the layout ends up saved.

GNOME behaves differently. Mutter's drag grab cancels a client drag on Escape and consumes the key, so the overview stays open and nothing can drop.

Fix

  • Smithay 0.7.0 (vendored). Upstream has no way to cancel a client drag: unsetting DnDGrab runs its drop path. This PR ports v1: integrate latest proof candidate and refresh app folders #654's client_dnd_active / cancel_client_dnd. They mark the offer inactive under the grab lock, then unset the grab: the target gets leave, the source gets cancelled, and Accept/SetActions/Receive requests already in flight cannot revive the offer. A dead origin or source also cancels, and the terminal path runs once. The patch is documented in third-party/smithay/ROOST-PATCH.md with its isolated diff in DND-CANCEL-API-PATCH.diff.
  • Runtime. An Escape press while a client drag holds the pointer or touch cancels the drag and is consumed, along with its repeats and its release. The flag clears when the lock takes the keyboard. Plain Escape still closes the overview. The state file reports client_dnd_active.
  • Tests. v1: integrate latest proof candidate and refresh app folders #654's socketpair tests in crates/compositor/tests/data_device.rs cover pointer and touch drags, with and without an icon or a source, and a normal drop that still Receives and Finishes.
  • Proof. It waits for .client_dnd_active and presses Escape. It then requires client_dnd_active false with overview_open and overview_app_grid still true, and polls the shell until its arrows are back and its hints are gone, all before releasing the button. The old "Escape may close the overview, reopen it" branch is removed.

#654 carries the same Smithay/runtime hunks verbatim, so it should rebase cleanly over this. One difference: #654's own flake, "GTK drag cleanup did not restore arrow before release", is a proof race. It dumps AT-SPI once, right after client_dnd_active turns false, before GTK has processed the cancel. This proof polls instead.

Validation

Exact-head reruns of gtk-shell and journey are listed below as they finish.

@hanthor
hanthor force-pushed the fix/escape-cancels-client-drag branch from 41f06a4 to 80661d6 Compare October 15, 2026 12:43
@hanthor
hanthor changed the base branch from fix/grid-drag-page-flakes to main October 15, 2026 15:38
…does

G-GRID-DRAG-CANCEL flaked with "cancelled folder drag changed the saved
layout" (#655). The compositor consumed Escape to close the overview but
left the shell's Wayland drag running. The proof's release right after
Escape raced the shell hiding the grid: when the drop reached GTK first,
the grid tile under the pointer took it and saved a reorder the user had
cancelled (run 38518164407: the hover reflow fired, Escape closed the
overview, a drop landed, layout saved).

Mutter's drag grab cancels a client drag on Escape and consumes the key.
Smithay 0.7.0 cannot cancel one: unsetting its DnDGrab runs the drop path,
which still delivers wl_data_device.drop to an accepted offer. Port the
cancel API from #654 to the vendored Smithay (client_dnd_active and
cancel_client_dnd: mark the offer inactive under the grab lock, then
unset, so the target gets leave, the source cancelled, and in-flight
Accept/SetActions/Receive cannot revive it), documented in ROOST-PATCH.md
with its isolated diff. The runtime cancels on an Escape press while a
client drag holds the pointer or touch and consumes that press, its
repeats and its release; plain Escape still closes the overview. The
state file reports client_dnd_active.

The proof now waits for the drag to hold the pointer, presses Escape,
and requires the drag cancelled with the grid still open and the
shell's hints gone before it releases the button.

Fixes #655

Signed-off-by: James Reilly <jreilly1821@gmail.com>
@hanthor
hanthor force-pushed the fix/escape-cancels-client-drag branch from 80661d6 to 7d71288 Compare October 15, 2026 15:42
@hanthor
hanthor merged commit 8a6041d into main Oct 15, 2026
27 of 30 checks passed
hanthor added a commit that referenced this pull request Oct 15, 2026
- runtime: main's Escape-cancels-drag matches this branch's own; keep
  ours plus main's lock reset of the held Escape and its docs.
- notify: production new() applies GNOME's notification policy to the
  persisted center, then builds through the testable build().
- gtk-shell-proof: keep this branch's stricter grid-cancel gate (neutral
  point, frame and held-key baselines, ordinary Escape afterwards); main's
  G-NOTIFY-POLICY gate merges cleanly.
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.

[ci-maintainer] ci: gtk-shell test failure - grid drag cancel behavior flaking

1 participant