render DnD drag icon surface following cursor

When a client starts a drag with an icon surface, create a
wlr_scene_subsurface_tree in the overlay layer and position it
at the cursor. Update position on drag motion, destroy on end.
This commit is contained in:
lkn 2026-06-23 17:32:10 +02:00
parent b90908da6a
commit 467805da20
1 changed files with 22 additions and 0 deletions

View File

@ -7,12 +7,14 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_scene.h>
#include "wl_types.h"
#include <WINGs/WINGsP.h>
/* Currently active external wlr_drag (NULL if none). */
struct wlr_drag *wl_current_drag = NULL;
static struct wlr_scene_tree *drag_icon_tree = NULL;
void handle_drag_motion(struct wl_listener *listener, void *data);
void handle_drag_drop(struct wl_listener *listener, void *data);
@ -35,6 +37,17 @@ handle_seat_request_start_drag(struct wl_listener *listener, void *data)
wl_signal_add(&ev->drag->events.motion, &wl_drag_motion_listener);
wl_signal_add(&ev->drag->events.drop, &wl_drag_drop_listener);
wl_signal_add(&ev->drag->events.destroy, &wl_drag_destroy_listener);
/* Render the drag icon surface if provided */
if (ev->drag->icon && ev->drag->icon->surface && wl_state.scene) {
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
drag_icon_tree = wlr_scene_subsurface_tree_create(parent,
ev->drag->icon->surface);
if (drag_icon_tree)
wlr_scene_node_set_position(&drag_icon_tree->node,
(int)wl_state.pointer_x, (int)wl_state.pointer_y);
}
}
void
@ -47,6 +60,11 @@ handle_drag_motion(struct wl_listener *listener, void *data)
if (!wl_current_drag)
return;
/* Update drag icon position */
if (drag_icon_tree)
wlr_scene_node_set_position(&drag_icon_tree->node,
(int)wl_state.pointer_x, (int)wl_state.pointer_y);
/* Hit-test at current pointer position */
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
wl_state.pointer_y);
@ -140,5 +158,9 @@ handle_drag_destroy(struct wl_listener *listener, void *data)
(void)listener;
(void)data;
wwarning("wl_backend: external DND finished");
if (drag_icon_tree) {
wlr_scene_node_destroy(&drag_icon_tree->node);
drag_icon_tree = NULL;
}
wl_current_drag = NULL;
}