input/seat: track toplevel drag and move container during drag

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.
This commit is contained in:
Ryan Walklin 2025-12-12 21:01:55 +13:00
parent bad8a87f4c
commit c65b7477b5
4 changed files with 178 additions and 0 deletions

View file

@ -74,10 +74,22 @@ struct sway_seat_node {
struct wl_listener destroy;
};
struct wlr_xdg_toplevel_drag_v1;
struct sway_drag {
struct sway_seat *seat;
struct wlr_drag *wlr_drag;
struct wlr_xdg_toplevel_drag_v1 *toplevel_drag; // may be NULL
struct wlr_surface *origin; // surface where drag started
// For xdg-toplevel-drag: track the dragged surface ourselves rather than
// trusting wlroots' toplevel pointer, which may not be NULLed promptly
// during destruction sequences. This mirrors Mutter's approach.
struct wlr_surface *toplevel_surface; // the attached toplevel's surface
struct wl_listener toplevel_surface_destroy;
struct wl_listener destroy;
struct wl_listener motion;
};
struct sway_seat {
@ -93,6 +105,14 @@ struct sway_seat {
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *drag_icons;
// Container being dragged via xdg-toplevel-drag protocol.
// This container is skipped during hit testing so that
// drop targets underneath can receive pointer focus.
struct sway_container *toplevel_drag_container;
// Origin surface of pending drag (set in request_start_drag, used in start_drag)
struct wlr_surface *pending_drag_origin;
bool has_focus;
struct wl_list focus_stack; // list of containers in focus order
struct sway_workspace *workspace;

View file

@ -233,6 +233,12 @@ void container_get_box(struct sway_container *container, struct wlr_box *box);
void container_floating_translate(struct sway_container *con,
double x_amount, double y_amount);
/**
* Update scene graph position immediately for a floating container.
* Used during drag operations for smoother visual feedback.
*/
void container_floating_update_scene_position(struct sway_container *con);
/**
* Choose an output for the floating container's new position.
*/