From 885bf8f5e8aaf5b635cd49574b8939a2f1101b81 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 5 Dec 2024 20:21:56 +0100 Subject: [PATCH] xwayland: listen to drag focus destroy signal The wlr_drag takes care of resetting the focused wlr_surface when it's destroyed, however we store the wlr_xwayland_surface, which may be destroyed before. (cherry picked from commit c7acfe906bae81f395a12b3351c320a56b559fc2) --- include/xwayland/xwm.h | 1 + xwayland/selection/dnd.c | 53 ++++++++++++++++++++++++++++------------ xwayland/xwm.c | 1 + 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index fe15fda50..34e1783d5 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -144,6 +144,7 @@ struct wlr_xwm { struct wl_listener seat_drag_drop; struct wl_listener seat_drag_destroy; struct wl_listener seat_drag_source_destroy; + struct wl_listener drag_focus_destroy; }; struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd); diff --git a/xwayland/selection/dnd.c b/xwayland/selection/dnd.c index 30084892d..a3b9fa7ff 100644 --- a/xwayland/selection/dnd.c +++ b/xwayland/selection/dnd.c @@ -234,6 +234,37 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, } } +static void xwm_set_drag_focus(struct wlr_xwm *xwm, struct wlr_xwayland_surface *focus); + +static void drag_focus_handle_destroy(struct wl_listener *listener, void *data) { + struct wlr_xwm *xwm = wl_container_of(listener, xwm, drag_focus_destroy); + xwm_set_drag_focus(xwm, NULL); +} + +static void xwm_set_drag_focus(struct wlr_xwm *xwm, struct wlr_xwayland_surface *focus) { + if (focus == xwm->drag_focus) { + return; + } + + if (xwm->drag_focus != NULL) { + wlr_data_source_dnd_action(xwm->drag->source, + WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); + xwm_dnd_send_leave(xwm); + } + + wl_list_remove(&xwm->drag_focus_destroy.link); + wl_list_init(&xwm->drag_focus_destroy.link); + + xwm->drag_focus = focus; + + if (xwm->drag_focus != NULL) { + xwm->drag_focus_destroy.notify = drag_focus_handle_destroy; + wl_signal_add(&xwm->drag_focus->events.destroy, &xwm->drag_focus_destroy); + + xwm_dnd_send_enter(xwm); + } +} + static void seat_handle_drag_focus(struct wl_listener *listener, void *data) { struct wlr_drag *drag = data; struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_focus); @@ -250,21 +281,7 @@ static void seat_handle_drag_focus(struct wl_listener *listener, void *data) { } } - if (focus == xwm->drag_focus) { - return; - } - - if (xwm->drag_focus != NULL) { - wlr_data_source_dnd_action(drag->source, - WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); - xwm_dnd_send_leave(xwm); - } - - xwm->drag_focus = focus; - - if (xwm->drag_focus != NULL) { - xwm_dnd_send_enter(xwm); - } + xwm_set_drag_focus(xwm, focus); } static void seat_handle_drag_motion(struct wl_listener *listener, void *data) { @@ -316,10 +333,15 @@ static void seat_handle_drag_source_destroy(struct wl_listener *listener, wl_list_remove(&xwm->seat_drag_source_destroy.link); wl_list_init(&xwm->seat_drag_source_destroy.link); + wl_list_remove(&xwm->drag_focus_destroy.link); + wl_list_init(&xwm->drag_focus_destroy.link); xwm->drag_focus = NULL; } void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag) { + wl_list_remove(&xwm->drag_focus_destroy.link); + wl_list_init(&xwm->drag_focus_destroy.link); + xwm->drag = drag; xwm->drag_focus = NULL; @@ -341,6 +363,7 @@ void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag) { void xwm_seat_unlink_drag_handlers(struct wlr_xwm *xwm) { wl_list_remove(&xwm->seat_drag_source_destroy.link); + wl_list_remove(&xwm->drag_focus_destroy.link); if (!xwm->drag) { return; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a1c597852..34208e97a 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -2176,6 +2176,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { wl_list_init(&xwm->unpaired_surfaces); wl_list_init(&xwm->pending_startup_ids); wl_list_init(&xwm->seat_drag_source_destroy.link); + wl_list_init(&xwm->drag_focus_destroy.link); xwm->ping_timeout = 10000;