From 6291e8453247053d2a706da7e1a5d7271e1774d2 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 Jan 2019 18:36:19 +0100 Subject: data-device: refactor wlr_drag --- include/wlr/types/wlr_data_device.h | 76 +++++++++++++++++++++++++++---------- include/wlr/types/wlr_seat.h | 31 ++++++++++++++- 2 files changed, 86 insertions(+), 21 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 59aa718f..9da7cc0d 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -89,15 +89,13 @@ struct wlr_data_source { } events; }; +struct wlr_drag; + struct wlr_drag_icon { + struct wlr_drag *drag; struct wlr_surface *surface; - struct wlr_seat_client *client; - struct wl_list link; // wlr_seat::drag_icons bool mapped; - bool is_pointer; - int32_t touch_id; - struct { struct wl_signal map; struct wl_signal unmap; @@ -105,40 +103,46 @@ struct wlr_drag_icon { } events; struct wl_listener surface_destroy; - struct wl_listener seat_client_destroy; void *data; }; +enum wlr_drag_grab_type { + WLR_DRAG_GRAB_KEYBOARD, + WLR_DRAG_GRAB_KEYBOARD_POINTER, + WLR_DRAG_GRAB_KEYBOARD_TOUCH, +}; + struct wlr_drag { - struct wlr_seat_pointer_grab pointer_grab; + enum wlr_drag_grab_type grab_type; struct wlr_seat_keyboard_grab keyboard_grab; + struct wlr_seat_pointer_grab pointer_grab; struct wlr_seat_touch_grab touch_grab; struct wlr_seat *seat; struct wlr_seat_client *seat_client; struct wlr_seat_client *focus_client; - bool is_pointer_grab; + struct wlr_drag_icon *icon; // can be NULL + struct wlr_surface *focus; // can be NULL + struct wlr_data_source *source; // can be NULL - struct wlr_drag_icon *icon; - struct wlr_surface *focus; - struct wlr_data_source *source; + bool started, cancelling; + int32_t grab_touch_id, touch_id; // if WLR_DRAG_GRAB_TOUCH - bool cancelling; - int32_t grab_touch_id; + struct { + struct wl_signal focus; + struct wl_signal motion; // wlr_drag_motion_event + struct wl_signal drop; // wlr_drag_drop_event + struct wl_signal destroy; + } events; struct wl_listener point_destroy; struct wl_listener source_destroy; struct wl_listener seat_client_destroy; struct wl_listener icon_destroy; - struct { - struct wl_signal focus; - struct wl_signal motion; - struct wl_signal drop; - struct wl_signal destroy; - } events; + void *data; }; struct wlr_drag_motion_event { @@ -178,6 +182,40 @@ void wlr_seat_request_set_selection(struct wlr_seat *seat, void wlr_seat_set_selection(struct wlr_seat *seat, struct wlr_data_source *source, uint32_t serial); +/** + * Creates a new drag. To request to start the drag, call + * `wlr_seat_request_start_drag`. + */ +struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client, + struct wlr_data_source *source, struct wlr_surface *icon_surface); + +/** + * Requests a drag to be started on the seat. + */ +void wlr_seat_request_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, + struct wlr_surface *origin, uint32_t serial); + +/** + * Starts a drag on the seat. This starts an implicit keyboard grab, but doesn't + * start a pointer or a touch grab. + */ +void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, + uint32_t serial); + +/** + * Starts a pointer drag on the seat. This starts implicit keyboard and pointer + * grabs. + */ +void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag, + uint32_t serial); + +/** + * Starts a touch drag on the seat. This starts implicit keyboard and touch + * grabs. + */ +void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag, + uint32_t serial, struct wlr_touch_point *point); + /** * Initializes the data source with the provided implementation. */ diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index c81c2cec..c020dbdb 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -191,7 +191,6 @@ struct wlr_seat { struct wl_global *global; struct wl_display *display; struct wl_list clients; - struct wl_list drag_icons; // wlr_drag_icon::link char *name; uint32_t capabilities; @@ -239,8 +238,9 @@ struct wlr_seat { struct wl_signal request_set_primary_selection; struct wl_signal set_primary_selection; + // wlr_seat_request_start_drag_event + struct wl_signal request_start_drag; struct wl_signal start_drag; // wlr_drag - struct wl_signal new_drag_icon; // wlr_drag_icon struct wl_signal destroy; } events; @@ -265,6 +265,12 @@ struct wlr_seat_request_set_primary_selection_event { uint32_t serial; }; +struct wlr_seat_request_start_drag_event { + struct wlr_drag *drag; + struct wlr_surface *origin; + uint32_t serial; +}; + struct wlr_seat_pointer_focus_change_event { struct wlr_seat *seat; struct wlr_surface *old_surface, *new_surface; @@ -597,9 +603,30 @@ bool wlr_seat_touch_has_grab(struct wlr_seat *seat); */ bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial); +/** + * Check whether this serial is valid to start a pointer grab action. + */ +bool wlr_seat_validate_pointer_grab_serial(struct wlr_seat *seat, + struct wlr_surface *origin, uint32_t serial); + +/** + * Check whether this serial is valid to start a touch grab action. If it's the + * case and point_ptr is non-NULL, *point_ptr is set to the touch point matching + * the serial. + */ +bool wlr_seat_validate_touch_grab_serial(struct wlr_seat *seat, + struct wlr_surface *origin, uint32_t serial, + struct wlr_touch_point **point_ptr); + +/** + * Get a seat client from a seat resource. Returns NULL if inert. + */ struct wlr_seat_client *wlr_seat_client_from_resource( struct wl_resource *resource); +/** + * Get a seat client from a pointer resource. Returns NULL if inert. + */ struct wlr_seat_client *wlr_seat_client_from_pointer_resource( struct wl_resource *resource); -- cgit v1.2.3 From d6de6404403679b42721e484609c31243447a6f3 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 18 Feb 2019 12:34:21 +0100 Subject: data-device: unbreak wl_data_source.cancel during drag-and-drop --- include/wlr/types/wlr_data_device.h | 2 +- types/data_device/wlr_data_offer.c | 28 ++++++++--------- types/data_device/wlr_drag.c | 60 +++++++++++++++++++++++++------------ 3 files changed, 56 insertions(+), 34 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 9da7cc0d..256654e5 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -127,7 +127,7 @@ struct wlr_drag { struct wlr_surface *focus; // can be NULL struct wlr_data_source *source; // can be NULL - bool started, cancelling; + bool started, dropped, cancelling; int32_t grab_touch_id, touch_id; // if WLR_DRAG_GRAB_TOUCH struct { diff --git a/types/data_device/wlr_data_offer.c b/types/data_device/wlr_data_offer.c index 26b894ea..086feb11 100644 --- a/types/data_device/wlr_data_offer.c +++ b/types/data_device/wlr_data_offer.c @@ -111,20 +111,6 @@ static void data_offer_dnd_finish(struct wlr_data_offer *offer) { static void data_offer_handle_destroy(struct wl_client *client, struct wl_resource *resource) { - struct wlr_data_offer *offer = data_offer_from_resource(resource); - if (offer == NULL) { - goto out; - } - - // If the drag destination has version < 3, wl_data_offer.finish - // won't be called, so do this here as a safety net, because - // we still want the version >= 3 drag source to be happy. - if (wl_resource_get_version(offer->resource) < - WL_DATA_OFFER_ACTION_SINCE_VERSION) { - data_offer_dnd_finish(offer); - } - -out: wl_resource_destroy(resource); } @@ -204,6 +190,18 @@ void data_offer_destroy(struct wlr_data_offer *offer) { wl_list_remove(&offer->source_destroy.link); wl_list_remove(&offer->link); + if (offer->type == WLR_DATA_OFFER_DRAG) { + // If the drag destination has version < 3, wl_data_offer.finish + // won't be called, so do this here as a safety net, because + // we still want the version >= 3 drag source to be happy. + if (wl_resource_get_version(offer->resource) < + WL_DATA_OFFER_ACTION_SINCE_VERSION) { + data_offer_dnd_finish(offer); + } else if (offer->source && offer->source->impl->dnd_finish) { + wlr_data_source_destroy(offer->source); + } + } + // Make the resource inert wl_resource_set_user_data(offer->resource, NULL); @@ -227,6 +225,8 @@ static void data_offer_handle_source_destroy(struct wl_listener *listener, void *data) { struct wlr_data_offer *offer = wl_container_of(listener, offer, source_destroy); + // Prevent data_offer_destroy from destroying the source again + offer->source = NULL; data_offer_destroy(offer); } diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index bfdc04aa..ab0005d3 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -28,6 +28,20 @@ static void drag_set_focus(struct wlr_drag *drag, if (drag->focus_client) { wl_list_remove(&drag->seat_client_destroy.link); + // If we're switching focus to another client, we want to destroy all + // offers without destroying the source. If the drag operation ends, we + // want to keep the offer around for the data transfer. + struct wlr_data_offer *offer, *tmp; + wl_list_for_each_safe(offer, tmp, + &drag->focus_client->seat->drag_offers, link) { + struct wl_client *client = wl_resource_get_client(offer->resource); + if (!drag->dropped && offer->source == drag->source && + client == drag->focus_client->client) { + offer->source = NULL; + data_offer_destroy(offer); + } + } + struct wl_resource *resource; wl_resource_for_each(resource, &drag->focus_client->data_devices) { wl_data_device_send_leave(resource); @@ -37,20 +51,20 @@ static void drag_set_focus(struct wlr_drag *drag, drag->focus = NULL; } - if (!surface || !surface->resource) { - return; + if (!surface) { + goto out; } if (!drag->source && wl_resource_get_client(surface->resource) != drag->seat_client->client) { - return; + goto out; } 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; + goto out; } if (drag->source != NULL) { @@ -88,6 +102,7 @@ static void drag_set_focus(struct wlr_drag *drag, drag->seat_client_destroy.notify = drag_handle_seat_client_destroy; wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy); +out: wlr_signal_emit_safe(&drag->events.focus, drag); } @@ -164,6 +179,26 @@ static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab, } } +static void drag_drop(struct wlr_drag *drag, uint32_t time) { + assert(drag->focus_client); + + drag->dropped = true; + + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_drop(resource); + } + if (drag->source) { + wlr_data_source_dnd_drop(drag->source); + } + + struct wlr_drag_drop_event event = { + .drag = drag, + .time = time, + }; + wlr_signal_emit_safe(&drag->events.drop, &event); +} + static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab, uint32_t time, uint32_t button, uint32_t state) { struct wlr_drag *drag = grab->data; @@ -173,17 +208,7 @@ static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab, state == WL_POINTER_BUTTON_STATE_RELEASED) { if (drag->focus_client && drag->source->current_dnd_action && drag->source->accepted) { - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_drop(resource); - } - wlr_data_source_dnd_drop(drag->source); - - struct wlr_drag_drop_event event = { - .drag = drag, - .time = time, - }; - wlr_signal_emit_safe(&drag->events.drop, &event); + drag_drop(drag, time); } else if (drag->source->impl->dnd_finish) { // This will end the grab and free `drag` wlr_data_source_destroy(drag->source); @@ -233,10 +258,7 @@ static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab, } if (drag->focus_client) { - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_drop(resource); - } + drag_drop(drag, time); } drag_destroy(drag); -- cgit v1.2.3