diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index df1a3285b..ec81fa3c4 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -149,6 +149,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 5918b813a..536abe0c2 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 ee9a28233..f7537dacb 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -2265,6 +2265,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;