From 0d7a81ccdfda7d21ece47e0715a25bd301363cc2 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 28 Mar 2018 12:59:11 -0400 Subject: xwayland: send DND_ENTER --- include/wlr/types/wlr_data_device.h | 5 +++++ include/wlr/types/wlr_seat.h | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index ff4a0f7e..cefcc979 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -104,6 +104,11 @@ struct wlr_drag { struct wl_listener source_destroy; struct wl_listener seat_client_destroy; struct wl_listener icon_destroy; + + struct { + struct wl_signal focus; + struct wl_signal destroy; + } events; }; /** diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 124c1cb8..435a3e7e 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -187,6 +187,9 @@ struct wlr_seat { struct wlr_primary_selection_source *primary_selection_source; uint32_t primary_selection_serial; + struct wlr_drag *drag; + uint32_t drag_serial; + struct wlr_seat_pointer_state pointer_state; struct wlr_seat_keyboard_state keyboard_state; struct wlr_seat_touch_state touch_state; @@ -210,6 +213,7 @@ struct wlr_seat { struct wl_signal selection; struct wl_signal primary_selection; + struct wl_signal start_drag; struct wl_signal new_drag_icon; struct wl_signal destroy; -- cgit v1.2.3 From 73394deb761232ff6a5a12400fe9e9fc5ab51114 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 28 Mar 2018 14:16:14 -0400 Subject: xwayland: send DND_POSITION --- include/wlr/types/wlr_data_device.h | 7 +++ include/xwayland/xwm.h | 4 ++ types/wlr_data_device.c | 14 ++++-- xwayland/selection.c | 87 +++++++++++++++++++++++++++++++------ 4 files changed, 94 insertions(+), 18 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index cefcc979..cd266795 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -107,10 +107,17 @@ struct wlr_drag { struct { struct wl_signal focus; + struct wl_signal motion; struct wl_signal destroy; } events; }; +struct wlr_drag_motion_event { + struct wlr_drag *drag; + uint32_t time; + double sx, sy; +}; + /** * Create a wl data device manager global for this display. */ diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index e672a2df..d4795d3f 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -122,6 +122,9 @@ struct wlr_xwm { struct wl_list surfaces; // wlr_xwayland_surface::link struct wl_list unpaired_surfaces; // wlr_xwayland_surface::unpaired_link + struct wlr_drag *drag; + struct wlr_xwayland_surface *drag_focus; + const xcb_query_extension_reply_t *xfixes; #ifdef WLR_HAS_XCB_ERRORS xcb_errors_context_t *errors_context; @@ -133,6 +136,7 @@ struct wlr_xwm { struct wl_listener seat_primary_selection; struct wl_listener seat_start_drag; struct wl_listener seat_drag_focus; + struct wl_listener seat_drag_motion; struct wl_listener seat_drag_destroy; }; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 8129b173..beb13eec 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -495,9 +495,6 @@ static void wlr_drag_end(struct wlr_drag *drag) { } } -const struct -wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface; - static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab, struct wlr_surface *surface, double sx, double sy) { struct wlr_drag *drag = grab->data; @@ -507,12 +504,20 @@ static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab, static void pointer_drag_motion(struct wlr_seat_pointer_grab *grab, uint32_t time, double sx, double sy) { struct wlr_drag *drag = grab->data; - if (drag->focus != NULL&& drag->focus_client != NULL) { + if (drag->focus != NULL && drag->focus_client != NULL) { struct wl_resource *resource; wl_resource_for_each(resource, &drag->focus_client->data_devices) { wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); } + + struct wlr_drag_motion_event event = { + .drag = drag, + .time = time, + .sx = sx, + .sy = sy, + }; + wlr_signal_emit_safe(&drag->events.motion, &event); } } @@ -739,6 +744,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.destroy); struct wlr_seat *seat = client->seat; diff --git a/xwayland/selection.c b/xwayland/selection.c index 8e5905df..d1dfbdaa 100644 --- a/xwayland/selection.c +++ b/xwayland/selection.c @@ -12,7 +12,7 @@ static const size_t incr_chunk_size = 64 * 1024; -/*static xcb_atom_t data_device_manager_dnd_action_to_atom( +static xcb_atom_t data_device_manager_dnd_action_to_atom( struct wlr_xwm *xwm, enum wl_data_device_manager_dnd_action action) { if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { return xwm->atoms[DND_ACTION_COPY]; @@ -24,7 +24,7 @@ static const size_t incr_chunk_size = 64 * 1024; return XCB_ATOM_NONE; } -static enum wl_data_device_manager_dnd_action +/*static enum wl_data_device_manager_dnd_action data_device_manager_dnd_action_from_atom(struct wlr_xwm *xwm, enum atom_name atom) { if (atom == xwm->atoms[DND_ACTION_COPY] || @@ -183,7 +183,8 @@ 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) { + if (selection == &selection->xwm->clipboard_selection || + selection == &selection->xwm->dnd_selection) { struct wlr_data_source *source = selection->xwm->seat->selection_data_source; if (source != NULL) { @@ -260,8 +261,9 @@ static xcb_atom_t xwm_get_mime_type_atom(struct wlr_xwm *xwm, char *mime_type) { return atom; } -static void xwm_dnd_send_enter(struct wlr_xwm *xwm, struct wlr_drag *drag, - struct wlr_xwayland_surface *dest) { +static void xwm_dnd_send_enter(struct wlr_xwm *xwm) { + struct wlr_drag *drag = xwm->drag; + struct wlr_xwayland_surface *dest = xwm->drag_focus; struct wl_array *mime_types = &drag->source->mime_types; xcb_client_message_data_t data = { 0 }; @@ -316,9 +318,38 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm, struct wlr_drag *drag, (const char *)&event); } +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; + struct wlr_xwayland_surface *dest = xwm->drag_focus; + + xcb_client_message_data_t data = { 0 }; + data.data32[0] = xwm->dnd_selection.window; + data.data32[2] = (x << 16) | y; + data.data32[3] = time; + data.data32[4] = + data_device_manager_dnd_action_to_atom(xwm, drag->source->actions); + + xcb_client_message_event_t event = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .sequence = 0, + .window = dest->window_id, + .type = xwm->atoms[DND_POSITION], + .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) { + if (selection == &selection->xwm->clipboard_selection || + selection == &selection->xwm->dnd_selection) { struct wlr_data_source *source = selection->xwm->seat->selection_data_source; if (source != NULL) { @@ -414,7 +445,7 @@ static void xwm_handle_selection_request(struct wlr_xwm *xwm, selection->flush_property_on_delete = 0; // No xwayland surface focused, deny access to clipboard - if (xwm->focus_surface == NULL) { + if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) { wlr_log(L_DEBUG, "denying read access to clipboard: " "no xwayland surface focused"); xwm_selection_send_notify(selection, XCB_ATOM_NONE); @@ -714,7 +745,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { // set the wayland selection to the X11 selection struct wlr_xwm *xwm = selection->xwm; - if (selection == &xwm->clipboard_selection) { + if (selection == &xwm->clipboard_selection || + selection == &xwm->dnd_selection) { struct x11_data_source *source = calloc(1, sizeof(struct x11_data_source)); if (source == NULL) { @@ -725,6 +757,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { source->base.send = data_source_send; source->base.cancel = data_source_cancel; + // TODO: DND + source->selection = selection; wl_array_init(&source->mime_types_atoms); @@ -816,6 +850,11 @@ static int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, } else if (selection == &xwm->primary_selection) { wlr_seat_set_primary_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); + } else if (selection == &xwm->dnd_selection) { + // TODO: DND + } else { + wlr_log(L_DEBUG, "X11 selection has been cleared, but cannot " + "clear Wayland selection"); } } @@ -1009,7 +1048,21 @@ static void seat_handle_drag_focus(struct wl_listener *listener, void *data) { return; } - xwm_dnd_send_enter(xwm, drag, surface); + xwm->drag_focus = surface; + xwm_dnd_send_enter(xwm); +} + +static void seat_handle_drag_motion(struct wl_listener *listener, void *data) { + struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_motion); + struct wlr_drag_motion_event *event = data; + struct wlr_xwayland_surface *surface = xwm->drag_focus; + + if (surface == NULL) { + return; // No xwayland surface focused + } + + xwm_dnd_send_position(xwm, event->time, surface->x + (int16_t)event->sx, + surface->y + (int16_t)event->sy); } static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) { @@ -1017,6 +1070,7 @@ static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwm->seat_drag_focus.link); wl_list_remove(&xwm->seat_drag_destroy.link); + xwm->drag = NULL; } static void seat_handle_start_drag(struct wl_listener *listener, void *data) { @@ -1024,11 +1078,16 @@ static void seat_handle_start_drag(struct wl_listener *listener, void *data) { struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_start_drag); xwm_selection_set_owner(&xwm->dnd_selection, drag != NULL); - - wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus); - xwm->seat_drag_focus.notify = seat_handle_drag_focus; - wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy); - xwm->seat_drag_destroy.notify = seat_handle_drag_destroy; + xwm->drag = drag; + + if (drag != NULL) { + wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus); + 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.destroy, &xwm->seat_drag_destroy); + xwm->seat_drag_destroy.notify = seat_handle_drag_destroy; + } } void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat) { -- cgit v1.2.3 From 2a34b154e683bb962aed354c1d980a7c10c66824 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 28 Mar 2018 15:33:23 -0400 Subject: xwayland: send DND_DROP --- include/wlr/types/wlr_data_device.h | 6 ++ include/xwayland/xwm.h | 3 + types/wlr_data_device.c | 9 ++- xwayland/selection.c | 107 +++++++++++++++++++++++++++++++++++- xwayland/xwm.c | 2 +- 5 files changed, 123 insertions(+), 4 deletions(-) (limited to 'include/wlr') 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); } } -- cgit v1.2.3 From 743466d475b744d818584db7f4040fd479c3f27e Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 29 Mar 2018 11:33:40 -0400 Subject: data-device: add seat.drag_source --- include/wlr/types/wlr_seat.h | 7 +++-- types/wlr_data_device.c | 66 +++++++++++++++++++++++++++----------------- types/wlr_seat.c | 8 +++--- 3 files changed, 50 insertions(+), 31 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 435a3e7e..34105cf0 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -181,13 +181,15 @@ struct wlr_seat { uint32_t capabilities; struct timespec last_event; - struct wlr_data_source *selection_data_source; + struct wlr_data_source *selection_source; uint32_t selection_serial; struct wlr_primary_selection_source *primary_selection_source; uint32_t primary_selection_serial; + // `drag` goes away before `drag_source`, when the implicit grab ends struct wlr_drag *drag; + struct wlr_data_source *drag_source; uint32_t drag_serial; struct wlr_seat_pointer_state pointer_state; @@ -195,8 +197,9 @@ struct wlr_seat { struct wlr_seat_touch_state touch_state; struct wl_listener display_destroy; - struct wl_listener selection_data_source_destroy; + struct wl_listener selection_source_destroy; struct wl_listener primary_selection_source_destroy; + struct wl_listener drag_source_destroy; struct { struct wl_signal pointer_grab_begin; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index f61ef07e..3e78760b 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -275,9 +275,9 @@ void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) { return; } - if (seat_client->seat->selection_data_source) { + if (seat_client->seat->selection_source) { struct wlr_data_offer *offer = wlr_data_source_send_offer( - seat_client->seat->selection_data_source, seat_client); + seat_client->seat->selection_source, seat_client); if (offer == NULL) { return; } @@ -294,10 +294,10 @@ void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) { } } -static void seat_client_selection_data_source_destroy( +static void seat_client_selection_source_destroy( struct wl_listener *listener, void *data) { struct wlr_seat *seat = - wl_container_of(listener, seat, selection_data_source_destroy); + wl_container_of(listener, seat, selection_source_destroy); struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client; if (seat_client && seat->keyboard_state.focused_surface) { @@ -307,7 +307,7 @@ static void seat_client_selection_data_source_destroy( } } - seat->selection_data_source = NULL; + seat->selection_source = NULL; wlr_signal_emit_safe(&seat->events.selection, seat); } @@ -319,18 +319,18 @@ void wlr_seat_set_selection(struct wlr_seat *seat, assert(source->cancel); } - if (seat->selection_data_source && + if (seat->selection_source && seat->selection_serial - serial < UINT32_MAX / 2) { return; } - if (seat->selection_data_source) { - seat->selection_data_source->cancel(seat->selection_data_source); - seat->selection_data_source = NULL; - wl_list_remove(&seat->selection_data_source_destroy.link); + if (seat->selection_source) { + seat->selection_source->cancel(seat->selection_source); + seat->selection_source = NULL; + wl_list_remove(&seat->selection_source_destroy.link); } - seat->selection_data_source = source; + seat->selection_source = source; seat->selection_serial = serial; struct wlr_seat_client *focused_client = @@ -343,10 +343,10 @@ void wlr_seat_set_selection(struct wlr_seat *seat, wlr_signal_emit_safe(&seat->events.selection, seat); if (source) { - seat->selection_data_source_destroy.notify = - seat_client_selection_data_source_destroy; + seat->selection_source_destroy.notify = + seat_client_selection_source_destroy; wl_signal_add(&source->events.destroy, - &seat->selection_data_source_destroy); + &seat->selection_source_destroy); } } @@ -571,8 +571,8 @@ static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) { wlr_drag_end(drag); } -const struct -wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface = { +static const struct wlr_pointer_grab_interface + data_device_pointer_drag_interface = { .enter = pointer_drag_enter, .motion = pointer_drag_motion, .button = pointer_drag_button, @@ -627,7 +627,8 @@ static void touch_drag_cancel(struct wlr_seat_touch_grab *grab) { wlr_drag_end(drag); } -const struct wlr_touch_grab_interface wlr_data_device_touch_drag_interface = { +static const struct wlr_touch_grab_interface + data_device_touch_drag_interface = { .down = touch_drag_down, .up = touch_drag_up, .motion = touch_drag_motion, @@ -658,8 +659,8 @@ static void keyboard_drag_cancel(struct wlr_seat_keyboard_grab *grab) { wlr_drag_end(drag); } -const struct -wlr_keyboard_grab_interface wlr_data_device_keyboard_drag_interface = { +static const struct wlr_keyboard_grab_interface + data_device_keyboard_drag_interface = { .enter = keyboard_drag_enter, .key = keyboard_drag_key, .modifiers = keyboard_drag_modifiers, @@ -743,6 +744,14 @@ static struct wlr_drag_icon *wlr_drag_icon_create( return icon; } +static void seat_handle_drag_source_destroy(struct wl_listener *listener, + void *data) { + struct wlr_seat *seat = + wl_container_of(listener, seat, drag_source_destroy); + wl_list_remove(&seat->drag_source_destroy.link); + seat->drag_source = NULL; +} + static bool seat_client_start_drag(struct wlr_seat_client *client, struct wlr_data_source *source, struct wlr_surface *icon_surface, struct wlr_surface *origin, uint32_t serial) { @@ -798,22 +807,22 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, wl_signal_add(&icon->events.destroy, &drag->icon_destroy); } - if (source) { + drag->source = source; + if (source != NULL) { drag->source_destroy.notify = drag_handle_drag_source_destroy; wl_signal_add(&source->events.destroy, &drag->source_destroy); - drag->source = source; } drag->seat_client = client; drag->pointer_grab.data = drag; - drag->pointer_grab.interface = &wlr_data_device_pointer_drag_interface; + drag->pointer_grab.interface = &data_device_pointer_drag_interface; drag->touch_grab.data = drag; - drag->touch_grab.interface = &wlr_data_device_touch_drag_interface; + drag->touch_grab.interface = &data_device_touch_drag_interface; drag->grab_touch_id = seat->touch_state.grab_id; drag->keyboard_grab.data = drag; - drag->keyboard_grab.interface = &wlr_data_device_keyboard_drag_interface; + drag->keyboard_grab.interface = &data_device_keyboard_drag_interface; wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab); @@ -828,6 +837,13 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, seat->drag = drag; // TODO: unset this thing somewhere seat->drag_serial = serial; + + seat->drag_source = source; + if (source != NULL) { + seat->drag_source_destroy.notify = seat_handle_drag_source_destroy; + wl_signal_add(&source->events.destroy, &seat->drag_source_destroy); + } + wlr_signal_emit_safe(&seat->events.start_drag, drag); return true; @@ -1069,7 +1085,7 @@ static void data_device_manager_create_data_source(struct wl_client *client, } static const struct wl_data_device_manager_interface -data_device_manager_impl = { + data_device_manager_impl = { .create_data_source = data_device_manager_create_data_source, .get_data_device = data_device_manager_get_data_device, }; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 53659f90..ed7fb470 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -365,10 +365,10 @@ void wlr_seat_destroy(struct wlr_seat *seat) { wl_list_remove(&seat->display_destroy.link); - if (seat->selection_data_source) { - seat->selection_data_source->cancel(seat->selection_data_source); - seat->selection_data_source = NULL; - wl_list_remove(&seat->selection_data_source_destroy.link); + if (seat->selection_source) { + seat->selection_source->cancel(seat->selection_source); + seat->selection_source = NULL; + wl_list_remove(&seat->selection_source_destroy.link); } if (seat->primary_selection_source) { seat->primary_selection_source->cancel(seat->primary_selection_source); -- cgit v1.2.3 From d5f46f4db4b646faad33f91b1677e46665871e6e Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 29 Mar 2018 17:53:13 -0400 Subject: data-device: redesign wlr_data_source --- include/wlr/types/wlr_data_device.h | 82 ++++++++++++++-- types/wlr_data_device.c | 180 ++++++++++++++++++++++++------------ types/wlr_seat.c | 4 +- 3 files changed, 193 insertions(+), 73 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 6733980a..6fb41c29 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -30,23 +30,29 @@ struct wlr_data_offer { struct wl_listener source_destroy; }; -struct wlr_data_source { - // source metadata - struct wl_array mime_types; - int32_t actions; - - // source implementation +/** + * A data source implementation. Only the `send` function is mandatory. Refer to + * the matching wl_data_source_* functions documentation to know what they do. + */ +struct wlr_data_source_impl { void (*send)(struct wlr_data_source *source, const char *mime_type, int32_t fd); void (*accept)(struct wlr_data_source *source, uint32_t serial, const char *mime_type); void (*cancel)(struct wlr_data_source *source); - // drag'n'drop implementation void (*dnd_drop)(struct wlr_data_source *source); void (*dnd_finish)(struct wlr_data_source *source); void (*dnd_action)(struct wlr_data_source *source, enum wl_data_device_manager_dnd_action action); +}; + +struct wlr_data_source { + const struct wlr_data_source_impl *impl; + + // source metadata + struct wl_array mime_types; + int32_t actions; // source status bool accepted; @@ -128,7 +134,7 @@ struct wlr_drag_drop_event { * Create a wl data device manager global for this display. */ struct wlr_data_device_manager *wlr_data_device_manager_create( - struct wl_display *display); + struct wl_display *display); /** * Destroys a wlr_data_device_manager and removes its wl_data_device_manager global. @@ -144,11 +150,67 @@ void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager); */ void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client); +/** + * Sets the current selection for the seat. This removes the previous one if + * there was any. + */ void wlr_seat_set_selection(struct wlr_seat *seat, - struct wlr_data_source *source, uint32_t serial); + struct wlr_data_source *source, uint32_t serial); -void wlr_data_source_init(struct wlr_data_source *source); +/** + * Initializes the data source with the provided implementation. + */ +void wlr_data_source_init(struct wlr_data_source *source, + const struct wlr_data_source_impl *impl); +/** + * Finishes the data source. + */ void wlr_data_source_finish(struct wlr_data_source *source); +/** + * Sends the data as the specified MIME type over the passed file descriptor, + * then close it. + */ +void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type, + int32_t fd); + +/** + * Notifies the data source that a target accepts one of the offered MIME types. + * If a target doesn't accept any of the offered types, `mime_type` is NULL. + */ +void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial, + const char *mime_type); + +/** + * Notifies the data source it is no longer valid and should be destroyed. That + * potentially destroys immediately the data source. + */ +void wlr_data_source_cancel(struct wlr_data_source *source); + +/** + * Notifies the data source that the drop operation was performed. This does not + * indicate acceptance. + * + * The data source may still be used in the future and should not be destroyed + * here. + */ +void wlr_data_source_dnd_drop(struct wlr_data_source *source); + +/** + * Notifies the data source that the drag-and-drop operation concluded. That + * potentially destroys immediately the data source. + */ +void wlr_data_source_dnd_finish(struct wlr_data_source *source); + +/** + * Notifies the data source that a target accepts the drag with the specified + * action. + * + * This shouldn't be called after `wlr_data_source_dnd_drop` unless the + * drag-and-drop operation ended in an "ask" action. + */ +void wlr_data_source_dnd_action(struct wlr_data_source *source, + enum wl_data_device_manager_dnd_action action); + #endif diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 3e78760b..13b1d08a 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -84,9 +84,7 @@ static void data_offer_update_action(struct wlr_data_offer *offer) { return; } - if (offer->source->dnd_action) { - offer->source->dnd_action(offer->source, action); - } + wlr_data_source_dnd_action(offer->source, action); if (wl_resource_get_version(offer->resource) >= WL_DATA_OFFER_ACTION_SINCE_VERSION) { @@ -104,10 +102,7 @@ static void data_offer_accept(struct wl_client *client, // TODO check that client is currently focused by the input device - if (offer->source->accept) { - offer->source->accept(offer->source, serial, mime_type); - } - offer->source->accepted = (mime_type != NULL); + wlr_data_source_accept(offer->source, serial, mime_type); } static void data_offer_receive(struct wl_client *client, @@ -115,7 +110,7 @@ static void data_offer_receive(struct wl_client *client, struct wlr_data_offer *offer = data_offer_from_resource(resource); if (offer->source && offer == offer->source->offer) { - offer->source->send(offer->source, mime_type, fd); + wlr_data_source_send(offer->source, mime_type, fd); } else { close(fd); } @@ -131,15 +126,12 @@ static void data_source_notify_finish(struct wlr_data_source *source) { return; } - if (source->offer->in_ask && source->dnd_action) { - source->dnd_action(source, source->current_dnd_action); - } - - if (source->dnd_finish) { - source->dnd_finish(source); + if (source->offer->in_ask) { + wlr_data_source_dnd_action(source, source->current_dnd_action); } source->offer = NULL; + wlr_data_source_dnd_finish(source); } static void data_offer_finish(struct wl_client *client, @@ -199,10 +191,10 @@ static void data_offer_resource_destroy(struct wl_resource *resource) { WL_DATA_OFFER_ACTION_SINCE_VERSION) { data_source_notify_finish(offer->source); offer->source->offer = NULL; - } else if (offer->source->dnd_finish) { + } else if (offer->source->impl->dnd_finish) { // source->cancel can free the source offer->source->offer = NULL; - offer->source->cancel(offer->source); + wlr_data_source_cancel(offer->source); } else { offer->source->offer = NULL; } @@ -314,20 +306,15 @@ static void seat_client_selection_source_destroy( void wlr_seat_set_selection(struct wlr_seat *seat, struct wlr_data_source *source, uint32_t serial) { - if (source) { - assert(source->send); - assert(source->cancel); - } - if (seat->selection_source && seat->selection_serial - serial < UINT32_MAX / 2) { return; } if (seat->selection_source) { - seat->selection_source->cancel(seat->selection_source); - seat->selection_source = NULL; wl_list_remove(&seat->selection_source_destroy.link); + wlr_data_source_cancel(seat->selection_source); + seat->selection_source = NULL; } seat->selection_source = source; @@ -533,9 +520,7 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, wl_resource_for_each(resource, &drag->focus_client->data_devices) { wl_data_device_send_drop(resource); } - if (drag->source->dnd_drop) { - drag->source->dnd_drop(drag->source); - } + wlr_data_source_dnd_drop(drag->source); if (drag->source->offer != NULL) { drag->source->offer->in_ask = @@ -548,8 +533,8 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, .time = time, }; wlr_signal_emit_safe(&drag->events.drop, &event); - } else if (drag->source->dnd_finish) { - drag->source->cancel(drag->source); + } else if (drag->source->impl->dnd_finish) { + wlr_data_source_cancel(drag->source); } } @@ -899,36 +884,51 @@ static void data_device_destroy(struct wl_resource *resource) { struct client_data_source { struct wlr_data_source source; + struct wlr_data_source_impl impl; struct wl_resource *resource; }; +static void client_data_source_accept(struct wlr_data_source *wlr_source, + uint32_t serial, const char *mime_type); + +static struct client_data_source *client_data_source_from_wlr_data_source( + struct wlr_data_source *wlr_source) { + assert(wlr_source->impl->accept == client_data_source_accept); + return (struct client_data_source *)wlr_source; +} + static void client_data_source_accept(struct wlr_data_source *wlr_source, uint32_t serial, const char *mime_type) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); wl_data_source_send_target(source->resource, mime_type); } static void client_data_source_send(struct wlr_data_source *wlr_source, const char *mime_type, int32_t fd) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); wl_data_source_send_send(source->resource, mime_type, fd); close(fd); } static void client_data_source_cancel(struct wlr_data_source *wlr_source) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); wl_data_source_send_cancelled(source->resource); } static void client_data_source_dnd_drop(struct wlr_data_source *wlr_source) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); assert(wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION); wl_data_source_send_dnd_drop_performed(source->resource); } static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); assert(wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION); wl_data_source_send_dnd_finished(source->resource); @@ -936,7 +936,8 @@ static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) { static void client_data_source_dnd_action(struct wlr_data_source *wlr_source, enum wl_data_device_manager_dnd_action action) { - struct client_data_source *source = (struct client_data_source *)wlr_source; + struct client_data_source *source = + client_data_source_from_wlr_data_source(wlr_source); assert(wl_resource_get_version(source->resource) >= WL_DATA_SOURCE_ACTION_SINCE_VERSION); wl_data_source_send_action(source->resource, action); @@ -947,6 +948,37 @@ static void data_source_destroy(struct wl_client *client, wl_resource_destroy(resource); } +static struct client_data_source *client_data_source_create( + struct wl_resource *source_resource) { + struct client_data_source *source = + calloc(1, sizeof(struct client_data_source)); + if (source == NULL) { + return NULL; + } + + source->resource = source_resource; + + source->impl.accept = client_data_source_accept; + source->impl.send = client_data_source_send; + source->impl.cancel = client_data_source_cancel; + + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { + source->impl.dnd_drop = client_data_source_dnd_drop; + } + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + source->impl.dnd_finish = client_data_source_dnd_finish; + } + if (wl_resource_get_version(source->resource) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + source->impl.dnd_action = client_data_source_dnd_action; + } + + wlr_data_source_init(&source->source, &source->impl); + return source; +} + static void data_source_set_actions(struct wl_client *client, struct wl_resource *resource, uint32_t dnd_actions) { struct client_data_source *source = @@ -1007,7 +1039,11 @@ static void data_source_resource_handle_destroy(struct wl_resource *resource) { free(source); } -void wlr_data_source_init(struct wlr_data_source *source) { +void wlr_data_source_init(struct wlr_data_source *source, + const struct wlr_data_source_impl *impl) { + assert(impl->send); + + source->impl = impl; wl_array_init(&source->mime_types); wl_signal_init(&source->events.destroy); source->actions = -1; @@ -1027,6 +1063,45 @@ void wlr_data_source_finish(struct wlr_data_source *source) { wl_array_release(&source->mime_types); } +void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type, + int32_t fd) { + source->impl->send(source, mime_type, fd); +} + +void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial, + const char *mime_type) { + source->accepted = (mime_type != NULL); + if (source->impl->accept) { + source->impl->accept(source, serial, mime_type); + } +} + +void wlr_data_source_cancel(struct wlr_data_source *source) { + if (source->impl->cancel) { + source->impl->cancel(source); + } +} + +void wlr_data_source_dnd_drop(struct wlr_data_source *source) { + if (source->impl->dnd_drop) { + source->impl->dnd_drop(source); + } +} + +void wlr_data_source_dnd_finish(struct wlr_data_source *source) { + if (source->impl->dnd_finish) { + source->impl->dnd_finish(source); + } +} + +void wlr_data_source_dnd_action(struct wlr_data_source *source, + enum wl_data_device_manager_dnd_action action) { + source->current_dnd_action = action; + if (source->impl->dnd_action) { + source->impl->dnd_action(source, action); + } +} + void data_device_manager_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, @@ -1048,40 +1123,23 @@ void data_device_manager_get_data_device(struct wl_client *client, static void data_device_manager_create_data_source(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - struct client_data_source *source = - calloc(1, sizeof(struct client_data_source)); - if (source == NULL) { + struct wl_resource *source_resource = wl_resource_create(client, + &wl_data_source_interface, wl_resource_get_version(resource), id); + if (source_resource == NULL) { wl_resource_post_no_memory(resource); return; } - wlr_data_source_init(&source->source); - source->resource = wl_resource_create(client, &wl_data_source_interface, - wl_resource_get_version(resource), id); - if (source->resource == NULL) { - free(source); + struct client_data_source *source = + client_data_source_create(source_resource); + if (source == NULL) { + wl_resource_destroy(source_resource); wl_resource_post_no_memory(resource); return; } - wl_resource_set_implementation(source->resource, &data_source_impl, - source, data_source_resource_handle_destroy); - source->source.accept = client_data_source_accept; - source->source.send = client_data_source_send; - source->source.cancel = client_data_source_cancel; - - if (wl_resource_get_version(source->resource) >= - WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { - source->source.dnd_drop = client_data_source_dnd_drop; - } - if (wl_resource_get_version(source->resource) >= - WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { - source->source.dnd_finish = client_data_source_dnd_finish; - } - if (wl_resource_get_version(source->resource) >= - WL_DATA_SOURCE_ACTION_SINCE_VERSION) { - source->source.dnd_action = client_data_source_dnd_action; - } + wl_resource_set_implementation(source_resource, &data_source_impl, + source, data_source_resource_handle_destroy); } static const struct wl_data_device_manager_interface diff --git a/types/wlr_seat.c b/types/wlr_seat.c index ed7fb470..3c1f17fa 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -366,9 +366,9 @@ void wlr_seat_destroy(struct wlr_seat *seat) { wl_list_remove(&seat->display_destroy.link); if (seat->selection_source) { - seat->selection_source->cancel(seat->selection_source); - seat->selection_source = NULL; wl_list_remove(&seat->selection_source_destroy.link); + wlr_data_source_cancel(seat->selection_source); + seat->selection_source = NULL; } if (seat->primary_selection_source) { seat->primary_selection_source->cancel(seat->primary_selection_source); -- cgit v1.2.3