fix DnD: drag icon follows cursor, clean up listeners

Update drag_icon_tree position in handle_pointer_motion so the icon
follows the cursor during drag. Use wlr_scene_drag_icon_create for
proper lifecycle. Remove listeners in handle_drag_destroy. Always
forward button releases so drags end correctly.
This commit is contained in:
lkn 2026-06-23 17:35:20 +02:00
parent ce696a72a0
commit 976bcce34c
4 changed files with 36 additions and 33 deletions

View File

@ -14,7 +14,7 @@
/* Currently active external wlr_drag (NULL if none). */
struct wlr_drag *wl_current_drag = NULL;
static struct wlr_scene_tree *drag_icon_tree = NULL;
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);
@ -38,12 +38,11 @@ handle_seat_request_start_drag(struct wl_listener *listener, void *data)
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) {
/* Render the drag icon using wlroots' built-in scene helper */
if (ev->drag->icon && 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);
drag_icon_tree = wlr_scene_drag_icon_create(parent, ev->drag->icon);
if (drag_icon_tree)
wlr_scene_node_set_position(&drag_icon_tree->node,
(int)wl_state.pointer_x, (int)wl_state.pointer_y);
@ -158,9 +157,12 @@ 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_list_remove(&wl_drag_motion_listener.link);
wl_list_remove(&wl_drag_drop_listener.link);
wl_list_remove(&wl_drag_destroy_listener.link);
wl_list_init(&wl_drag_motion_listener.link);
wl_list_init(&wl_drag_drop_listener.link);
wl_list_init(&wl_drag_destroy_listener.link);
drag_icon_tree = NULL;
wl_current_drag = NULL;
}

View File

@ -327,7 +327,9 @@ handle_pointer_button(struct wl_listener *listener, void *data)
}
}
if (forward_to_client && wl_state.seat->pointer_state.focused_surface) {
if (forward_to_client &&
(wl_state.seat->pointer_state.focused_surface ||
ev->state == WLR_BUTTON_RELEASED)) {
wlr_seat_pointer_notify_button(wl_state.seat, ev->time_msec,
ev->button, ev->state);
wlr_seat_pointer_notify_frame(wl_state.seat);

View File

@ -6,6 +6,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#include "../../screen.h"
#include "wl_types.h"
@ -144,6 +145,12 @@ handle_pointer_motion(struct wl_listener *listener, void *data)
}
if (wl_state.grab_type) { wl_grab_apply_motion(); return; }
wl_update_pointer_focus(ev->time_msec);
/* Update drag icon position if a drag is active */
extern struct wlr_scene_tree *drag_icon_tree;
if (drag_icon_tree)
wlr_scene_node_set_position(&drag_icon_tree->node,
wl_state.pointer_x, wl_state.pointer_y);
}
void

38
wm.log
View File

@ -1,25 +1,17 @@
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib64/libthread_db.so.1".
[New Thread 0x7fffe25ff6c0 (LWP 1941648)]
[New Thread 0x7fffe1dfe6c0 (LWP 1941649)]
[New Thread 0x7fffe11ff6c0 (LWP 1941650)]
[New Thread 0x7fffe09fe6c0 (LWP 1941651)]
[Thread 0x7fffe09fe6c0 (LWP 1941651) exited]
[Thread 0x7fffe11ff6c0 (LWP 1941650) exited]
[New Thread 0x7fffe11ff6c0 (LWP 1941652)]
[New Thread 0x7fffe09fe6c0 (LWP 1941653)]
[New Thread 0x7fffd3bff6c0 (LWP 1941654)]
[New Thread 0x7fffd33fe6c0 (LWP 1941655)]
[New Thread 0x7fffd29fd6c0 (LWP 1941656)]
[Detaching after vfork from child process 1941657]
[Detaching after fork from child process 1941658]
[Thread 0x7fffd33fe6c0 (LWP 1941655) exited]
[Thread 0x7fffd3bff6c0 (LWP 1941654) exited]
[Thread 0x7fffe09fe6c0 (LWP 1941653) exited]
[Thread 0x7fffe11ff6c0 (LWP 1941652) exited]
[Thread 0x7fffe1dfe6c0 (LWP 1941649) exited]
[Thread 0x7fffe25ff6c0 (LWP 1941648) exited]
[Thread 0x7ffff67c92c0 (LWP 1941645) exited]
[Thread 0x7fffd29fd6c0 (LWP 1941656) exited]
[New process 1941645]
[Inferior 1 (process 1941645) exited normally]
[New Thread 0x7fffe21ff6c0 (LWP 193764)]
[New Thread 0x7fffe19fe6c0 (LWP 193765)]
[New Thread 0x7fffe0dff6c0 (LWP 193766)]
[New Thread 0x7fffdbfff6c0 (LWP 193767)]
[Thread 0x7fffdbfff6c0 (LWP 193767) exited]
[Thread 0x7fffe0dff6c0 (LWP 193766) exited]
[New Thread 0x7fffe0dff6c0 (LWP 193768)]
[New Thread 0x7fffdbfff6c0 (LWP 193769)]
[New Thread 0x7fffdb7fe6c0 (LWP 193770)]
[New Thread 0x7fffdaffd6c0 (LWP 193771)]
[New Thread 0x7fffda5fc6c0 (LWP 193772)]
[Detaching after fork from child process 193773]
[Detaching after vfork from child process 193774]
[Detaching after fork from child process 193775]
[Detaching after fork from child process 193783]