Skip to content

Conversation

@tokyovigilante
Copy link
Contributor

Hi,

This PR implements support for xdg-toplevel-drag-v1, building on the wlroots PR here. Largely based on Mutter's implementation, and tested with Chromium's wayland backend.

Somewhat opinionated in that all secondary toplevels are created floating, which makes sense as it won't break existing tiled layouts and seems a better fit for tool palettes etc.

My first real deep dive into the scene graph and wlroots, so review and feedback appreciated.

toplevel_drag_trimmed.mp4

Add the xdg-toplevel-drag-v1 protocol manager to the server. This
protocol allows clients to attach a toplevel window to an ongoing
drag-and-drop operation, enabling features like browser tab tear-off.
Add support for tracking xdg-toplevel-drag operations and moving the
attached container during drag motion events.

Implementation detail:

- Track the dragged surface ourselves rather than trusting wlroots'
  toplevel pointer, which may not be NULLed promptly during destruction.
  This mirrors Mutter's approach with dragged_surface.

- Use find_xdg_view_with_toplevel_drag() which searches through sway's
  views and uses wlroots' wlr_xdg_toplevel_drag_v1_from_wlr_xdg_toplevel()
  for safe comparison, avoiding stale pointer access. There could be a
  better way to do this.

- Account for XDG surface geometry offset when positioning the container.

- Add container_floating_update_scene_position() helper that updates the
  scene graph position immediately, bypassing the transaction system's
  batching for smoother visual feedback during drag operations.

- Clean up container tracking in seatop_unref when container is destroyed.
Make toplevels attached to an xdg-toplevel-drag automatically float, and
position them at the cursor when first mapped.

This enables the typical tab tear-off workflow:
1. User starts dragging a tab in a browser
2. Browser creates a new toplevel attached to the drag
3. Sway floats the toplevel and positions it at the cursor
4. The motion handler (from previous commit) keeps it moving with cursor
Per the xdg-toplevel-drag protocol: "The attached window does not
participate in the selection of the drag target."

When the cursor is over the dragged toplevel, temporarily disable its
scene node and perform a second hit test to find the surface underneath.
This allows drop targets to receive pointer focus while dragging.

Also maintain pointer focus on the drag origin surface when the cursor
moves outside all windows, preventing drag motion from stopping.
When a tiled container is attached to a toplevel drag (e.g., re-tearing
out a previously tabbed window), float it so it can be moved with the
cursor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant