diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index 34e1783d5..4386446d4 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -123,6 +123,7 @@ struct wlr_xwm { struct wlr_drag *drag; struct wlr_xwayland_surface *drag_focus; + struct wlr_xwayland_surface *drop_focus; const xcb_query_extension_reply_t *xfixes; const xcb_query_extension_reply_t *xres; @@ -145,6 +146,7 @@ struct wlr_xwm { struct wl_listener seat_drag_destroy; struct wl_listener seat_drag_source_destroy; struct wl_listener drag_focus_destroy; + struct wl_listener drop_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 c2f3b4f0b..d914dbac1 100644 --- a/xwayland/selection/dnd.c +++ b/xwayland/selection/dnd.c @@ -212,10 +212,10 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm, bool performed = data->data32[1] & 1; xcb_atom_t action_atom = data->data32[2]; - if (xwm->drag_focus == NULL || - target_window != xwm->drag_focus->window_id) { + if (xwm->drop_focus == NULL || + target_window != xwm->drop_focus->window_id) { wlr_log(WLR_DEBUG, "ignoring XdndFinished client message because " - "it doesn't match the finished drag focus window ID"); + "it doesn't match the finished drop focus window ID"); return 1; } @@ -241,6 +241,13 @@ static void drag_focus_handle_destroy(struct wl_listener *listener, void *data) xwm_set_drag_focus(xwm, NULL); } +static void drop_focus_handle_destroy(struct wl_listener *listener, void *data) { + struct wlr_xwm *xwm = wl_container_of(listener, xwm, drop_focus_destroy); + wl_list_remove(&xwm->drop_focus_destroy.link); + wl_list_init(&xwm->drop_focus_destroy.link); + xwm->drop_focus = NULL; +} + static void xwm_set_drag_focus(struct wlr_xwm *xwm, struct wlr_xwayland_surface *focus) { if (focus == xwm->drag_focus) { return; @@ -299,6 +306,12 @@ static void seat_handle_drag_drop(struct wl_listener *listener, void *data) { } wlr_log(WLR_DEBUG, "Wayland drag dropped over an Xwayland window"); + + xwm->drop_focus = xwm->drag_focus; + xwm->drop_focus_destroy.notify = drop_focus_handle_destroy; + wl_list_remove(&xwm->drop_focus_destroy.link); + wl_signal_add(&xwm->drop_focus->events.destroy, &xwm->drop_focus_destroy); + xwm_dnd_send_drop(xwm, event->time); } @@ -329,14 +342,21 @@ static void seat_handle_drag_source_destroy(struct wl_listener *listener, wl_list_remove(&xwm->drag_focus_destroy.link); wl_list_init(&xwm->drag_focus_destroy.link); xwm->drag_focus = NULL; + + wl_list_remove(&xwm->drop_focus_destroy.link); + wl_list_init(&xwm->drop_focus_destroy.link); + xwm->drop_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); + wl_list_remove(&xwm->drop_focus_destroy.link); + wl_list_init(&xwm->drop_focus_destroy.link); xwm->drag = drag; xwm->drag_focus = NULL; + xwm->drop_focus = NULL; if (drag != NULL) { wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus); @@ -357,6 +377,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); + wl_list_remove(&xwm->drop_focus_destroy.link); if (!xwm->drag) { return; diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 3f2e2c711..f78146ff6 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -410,8 +410,11 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm, return; } + bool dnd_allowed = selection == &xwm->dnd_selection + && (xwm->drag_focus != NULL || xwm->drop_focus != NULL); + // No xwayland surface focused, deny access to clipboard - if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) { + if (xwm->focus_surface == NULL && !dnd_allowed) { if (wlr_log_get_verbosity() >= WLR_DEBUG) { char *selection_name = xwm_get_atom_name(xwm, selection->atom); wlr_log(WLR_DEBUG, "denying read access to selection %u (%s): " diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 34208e97a..b315fa0fc 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -2177,6 +2177,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) { wl_list_init(&xwm->pending_startup_ids); wl_list_init(&xwm->seat_drag_source_destroy.link); wl_list_init(&xwm->drag_focus_destroy.link); + wl_list_init(&xwm->drop_focus_destroy.link); xwm->ping_timeout = 10000;