diff options
-rw-r--r-- | include/wlr/types/wlr_data_device.h | 6 | ||||
-rw-r--r-- | include/xwayland/xwm.h | 3 | ||||
-rw-r--r-- | types/wlr_data_device.c | 9 | ||||
-rw-r--r-- | xwayland/selection.c | 107 | ||||
-rw-r--r-- | xwayland/xwm.c | 2 |
5 files changed, 123 insertions, 4 deletions
diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index cd266795..6733980a 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -108,6 +108,7 @@ struct wlr_drag { struct { struct wl_signal focus; struct wl_signal motion; + struct wl_signal drop; struct wl_signal destroy; } events; }; @@ -118,6 +119,11 @@ struct wlr_drag_motion_event { double sx, sy; }; +struct wlr_drag_drop_event { + struct wlr_drag *drag; + uint32_t time; +}; + /** * Create a wl data device manager global for this display. */ diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index d4795d3f..b6b26227 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -137,6 +137,7 @@ struct wlr_xwm { struct wl_listener seat_start_drag; struct wl_listener seat_drag_focus; struct wl_listener seat_drag_motion; + struct wl_listener seat_drag_drop; struct wl_listener seat_drag_destroy; }; @@ -148,6 +149,8 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y); int xwm_handle_selection_event(struct wlr_xwm *xwm, xcb_generic_event_t *event); +int xwm_handle_selection_client_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) ; void xwm_selection_init(struct wlr_xwm *xwm); void xwm_selection_finish(struct wlr_xwm *xwm); diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index beb13eec..8cc2b0e3 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -426,7 +426,6 @@ static void wlr_drag_set_focus(struct wlr_drag *drag, struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client(drag->seat_client->seat, wl_resource_get_client(surface->resource)); - if (!focus_client) { return; } @@ -541,6 +540,12 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, drag->source->offer->in_ask = drag->source->current_dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + + struct wlr_drag_drop_event event = { + .drag = drag, + .time = time, + }; + wlr_signal_emit_safe(&drag->events.drop, &event); } else if (drag->source->dnd_finish) { drag->source->cancel(drag->source); } @@ -556,6 +561,7 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, static void pointer_drag_axis(struct wlr_seat_pointer_grab *grab, uint32_t time, enum wlr_axis_orientation orientation, double value) { + // This space is intentionally left blank } static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) { @@ -745,6 +751,7 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, wl_signal_init(&drag->events.focus); wl_signal_init(&drag->events.motion); + wl_signal_init(&drag->events.drop); wl_signal_init(&drag->events.destroy); struct wlr_seat *seat = client->seat; diff --git a/xwayland/selection.c b/xwayland/selection.c index d1dfbdaa..1e68c997 100644 --- a/xwayland/selection.c +++ b/xwayland/selection.c @@ -183,8 +183,7 @@ error_out: static void xwm_selection_source_send(struct wlr_xwm_selection *selection, const char *mime_type, int32_t fd) { - if (selection == &selection->xwm->clipboard_selection || - selection == &selection->xwm->dnd_selection) { + if (selection == &selection->xwm->clipboard_selection) { struct wlr_data_source *source = selection->xwm->seat->selection_data_source; if (source != NULL) { @@ -198,6 +197,15 @@ static void xwm_selection_source_send(struct wlr_xwm_selection *selection, source->send(source, mime_type, fd); return; } + } else if (selection == &selection->xwm->dnd_selection) { + if (selection->xwm->seat->drag != NULL) { + struct wlr_data_source *source = + selection->xwm->seat->drag->source; + if (source != NULL) { + source->send(source, mime_type, fd); + return; + } + } } wlr_log(L_DEBUG, "not sending selection: no selection source available"); @@ -263,7 +271,9 @@ static xcb_atom_t xwm_get_mime_type_atom(struct wlr_xwm *xwm, char *mime_type) { static void xwm_dnd_send_enter(struct wlr_xwm *xwm) { struct wlr_drag *drag = xwm->drag; + assert(drag != NULL); struct wlr_xwayland_surface *dest = xwm->drag_focus; + assert(dest != NULL); struct wl_array *mime_types = &drag->source->mime_types; xcb_client_message_data_t data = { 0 }; @@ -321,7 +331,9 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm) { static void xwm_dnd_send_position(struct wlr_xwm *xwm, uint32_t time, int16_t x, int16_t y) { struct wlr_drag *drag = xwm->drag; + assert(drag != NULL); struct wlr_xwayland_surface *dest = xwm->drag_focus; + assert(dest != NULL); xcb_client_message_data_t data = { 0 }; data.data32[0] = xwm->dnd_selection.window; @@ -346,6 +358,63 @@ static void xwm_dnd_send_position(struct wlr_xwm *xwm, uint32_t time, int16_t x, (const char *)&event); } +static void xwm_dnd_send_drop(struct wlr_xwm *xwm, uint32_t time) { + struct wlr_drag *drag = xwm->drag; + assert(drag != NULL); + struct wlr_xwayland_surface *dest = xwm->drag_focus; + assert(dest != NULL); + + xcb_client_message_data_t data = { 0 }; + data.data32[0] = xwm->dnd_selection.window; + data.data32[2] = time; + + xcb_client_message_event_t event = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .sequence = 0, + .window = dest->window_id, + .type = xwm->atoms[DND_DROP], + .data = data, + }; + + xcb_send_event(xwm->xcb_conn, + 0, // propagate + dest->window_id, + XCB_EVENT_MASK_NO_EVENT, + (const char *)&event); +} + +/*static void xwm_dnd_send_finished(struct wlr_xwm *xwm) { + struct wlr_drag *drag = xwm->drag; + assert(drag != NULL); + struct wlr_xwayland_surface *dest = xwm->drag_focus; + assert(dest != NULL); + + xcb_client_message_data_t data = { 0 }; + data.data32[0] = xwm->dnd_selection.window; + data.data32[1] = drag->source->accepted; + + if (drag->source->accepted) { + data.data32[2] = data_device_manager_dnd_action_to_atom(xwm, + drag->source->current_dnd_action); + } + + xcb_client_message_event_t event = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .sequence = 0, + .window = dest->window_id, + .type = xwm->atoms[DND_FINISHED], + .data = data, + }; + + xcb_send_event(xwm->xcb_conn, + 0, // propagate + dest->window_id, + XCB_EVENT_MASK_NO_EVENT, + (const char *)&event); +}*/ + static struct wl_array *xwm_selection_source_get_mime_types( struct wlr_xwm_selection *selection) { if (selection == &selection->xwm->clipboard_selection || @@ -911,6 +980,26 @@ int xwm_handle_selection_event(struct wlr_xwm *xwm, return 0; } +int xwm_handle_selection_client_message(struct wlr_xwm *xwm, + xcb_client_message_event_t *ev) { + if (ev->type == xwm->atoms[DND_STATUS]) { + struct wlr_drag *drag = xwm->drag; + if (drag == NULL) { + return 0; + } + + // xcb_client_message_data_t *data = &ev->data; + // xcb_window_t target_window = data->data32[0]; + // bool accepted = data->data32[1] & 1; + // xcb_atom_t action = data->data32[4]; + + // TODO: drag->source->dnd_action(data_device_manager_dnd_action_from_atom(xwm, action)) + return 1; + } else { + return 0; + } +} + static void selection_init(struct wlr_xwm *xwm, struct wlr_xwm_selection *selection, xcb_atom_t atom) { selection->xwm = xwm; @@ -1065,6 +1154,18 @@ static void seat_handle_drag_motion(struct wl_listener *listener, void *data) { surface->y + (int16_t)event->sy); } +static void seat_handle_drag_drop(struct wl_listener *listener, void *data) { + struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_drop); + struct wlr_drag_drop_event *event = data; + struct wlr_xwayland_surface *surface = xwm->drag_focus; + + if (surface == NULL) { + return; // No xwayland surface focused + } + + xwm_dnd_send_drop(xwm, event->time); +} + static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) { struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_destroy); @@ -1085,6 +1186,8 @@ static void seat_handle_start_drag(struct wl_listener *listener, void *data) { xwm->seat_drag_focus.notify = seat_handle_drag_focus; wl_signal_add(&drag->events.motion, &xwm->seat_drag_motion); xwm->seat_drag_motion.notify = seat_handle_drag_motion; + wl_signal_add(&drag->events.drop, &xwm->seat_drag_drop); + xwm->seat_drag_drop.notify = seat_handle_drag_drop; wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy); xwm->seat_drag_destroy.notify = seat_handle_drag_destroy; } diff --git a/xwayland/xwm.c b/xwayland/xwm.c index a1ac43d6..712e1602 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -943,7 +943,7 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm, xwm_handle_net_wm_state_message(xwm, ev); } else if (ev->type == xwm->atoms[_NET_WM_MOVERESIZE]) { xwm_handle_net_wm_moveresize_message(xwm, ev); - } else { + } else if (!xwm_handle_selection_client_message(xwm, ev)) { wlr_log(L_DEBUG, "unhandled x11 client message %u", ev->type); } } |