From f001f98cef158e37e9594b0dca5b4bf60f59f201 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 27 Nov 2018 18:41:46 +0100 Subject: [PATCH 1/5] gtk-primary-selection: refactor everything, untie from seat This commits completely refactors wlr_gtk_primary_selection. The goal is to remove gtk-primary-selection state from the seat and better handle inert resources where it makes sense. wlr_seat_client.primary_selection_devices has been removed and replaced by wlr_gtk_primary_selection_device. This allows us to make offers inert when the current selection is replaced. wlr_seat_set_primary_selection has been removed because it relied on wlr_seat instead of wlr_gtk_primary_selection_device_manager. A new function, wlr_gtk_primary_selection_device_manager_set_selection (candidate for the longest function name in wlroots) has been added. It doesn't take a serial anymore as serial checking only makes sense for set_selection requests coming from Wayland clients (serial checking is now done in the Wayland interface implementation). Since wlr_gtk_primary_selection_device_manager is now required to set the selection, a new function wlr_xwayland_set_gtk_primary_selection_device_manager (candidate number two for longest function name) has been added. Devices are now made inert when the seat goes away. Future work includes removing the last primary selection bits from the seat, mainly wlr_seat.primary_selection_source and wlr_seat.events.primary_selection, replacing those with new fields in wlr_gtk_primary_selection_device. Or maybe we could keep those in the seat and replace them with a re-usable interface (for future zwp_primary_selection_v1 support). We need to think how we'll sync these three protocols (GTK, X11 and wayland-protocols). See https://github.com/swaywm/wlroots/issues/1388 --- include/wlr/types/wlr_gtk_primary_selection.h | 41 ++- include/wlr/types/wlr_seat.h | 12 +- include/wlr/xwayland.h | 9 +- rootston/desktop.c | 11 +- types/seat/wlr_seat.c | 13 +- types/seat/wlr_seat_keyboard.c | 8 +- types/wlr_gtk_primary_selection.c | 339 ++++++++++++------ xwayland/selection/incoming.c | 13 +- xwayland/selection/selection.c | 7 +- xwayland/xwayland.c | 6 + 10 files changed, 314 insertions(+), 145 deletions(-) diff --git a/include/wlr/types/wlr_gtk_primary_selection.h b/include/wlr/types/wlr_gtk_primary_selection.h index f3410f69..e2019123 100644 --- a/include/wlr/types/wlr_gtk_primary_selection.h +++ b/include/wlr/types/wlr_gtk_primary_selection.h @@ -14,7 +14,8 @@ struct wlr_gtk_primary_selection_device_manager { struct wl_global *global; - struct wl_list resources; + struct wl_list resources; // wl_resource_get_link + struct wl_list devices; // wlr_gtk_primary_selection_device::link struct wl_listener display_destroy; @@ -25,6 +26,28 @@ struct wlr_gtk_primary_selection_device_manager { void *data; }; +/** + * A device is a per-seat object used to set and get the current selection. + */ +struct wlr_gtk_primary_selection_device { + struct wlr_gtk_primary_selection_device_manager *manager; + struct wlr_seat *seat; + struct wl_list link; // wlr_gtk_primary_selection_device_manager::devices + struct wl_list resources; // wl_resource_get_link + + struct wlr_gtk_primary_selection_source *source; + struct wl_list offers; // wlr_gtk_primary_selection_offer::link + + struct wl_listener seat_destroy; + struct wl_listener seat_focus_change; + struct wl_listener source_destroy; + + void *data; +}; + +/** + * A source is the sending side of a selection. + */ struct wlr_gtk_primary_selection_source { // source metadata struct wl_array mime_types; @@ -34,9 +57,6 @@ struct wlr_gtk_primary_selection_source { const char *mime_type, int32_t fd); void (*cancel)(struct wlr_gtk_primary_selection_source *source); - // source status - struct wlr_seat_client *seat_client; - struct { struct wl_signal destroy; } events; @@ -44,9 +64,15 @@ struct wlr_gtk_primary_selection_source { void *data; }; +/** + * An offer is the receiving side of a selection. When the selection is set, + * offers are created for the currently focused client and can be used to + * initiate the data transfer. + */ struct wlr_gtk_primary_selection_offer { struct wl_resource *resource; struct wlr_gtk_primary_selection_source *source; + struct wl_list link; // wlr_gtk_primary_selection_device::offers struct wl_listener source_destroy; @@ -58,9 +84,10 @@ struct wlr_gtk_primary_selection_device_manager * void wlr_gtk_primary_selection_device_manager_destroy( struct wlr_gtk_primary_selection_device_manager *manager); -void wlr_seat_client_send_gtk_primary_selection(struct wlr_seat_client *seat_client); -void wlr_seat_set_gtk_primary_selection(struct wlr_seat *seat, - struct wlr_gtk_primary_selection_source *source, uint32_t serial); +void wlr_gtk_primary_selection_device_manager_set_selection( + struct wlr_gtk_primary_selection_device_manager *manager, + struct wlr_seat *seat, + struct wlr_gtk_primary_selection_source *source); void wlr_gtk_primary_selection_source_init( struct wlr_gtk_primary_selection_source *source); diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 9670e6a5..f064c3bb 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -30,7 +30,6 @@ struct wlr_seat_client { struct wl_list keyboards; struct wl_list touches; struct wl_list data_devices; - struct wl_list primary_selection_devices; struct { struct wl_signal destroy; @@ -168,6 +167,10 @@ struct wlr_seat_keyboard_state { struct wlr_seat_keyboard_grab *grab; struct wlr_seat_keyboard_grab *default_grab; + + struct { + struct wl_signal focus_change; // wlr_seat_keyboard_focus_change_event + } events; }; struct wlr_seat_touch_state { @@ -194,6 +197,7 @@ struct wlr_seat { struct wlr_data_source *selection_source; uint32_t selection_serial; + // not owned by the seat struct wlr_gtk_primary_selection_source *primary_selection_source; uint32_t primary_selection_serial; @@ -208,7 +212,6 @@ struct wlr_seat { struct wl_listener display_destroy; struct wl_listener selection_source_destroy; - struct wl_listener primary_selection_source_destroy; struct wl_listener drag_source_destroy; struct { @@ -248,6 +251,11 @@ struct wlr_seat_pointer_focus_change_event { double sx, sy; }; +struct wlr_seat_keyboard_focus_change_event { + struct wlr_seat *seat; + struct wlr_surface *old_surface, *new_surface; +}; + /** * Allocates a new wlr_seat and adds a wl_seat global to the display. */ diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 8247aa15..9a7f0f07 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -18,6 +18,7 @@ struct wlr_xwm; struct wlr_xwayland_cursor; +struct wlr_gtk_primary_selection_device_manager; struct wlr_xwayland { pid_t pid; @@ -42,13 +43,15 @@ struct wlr_xwayland { struct wl_display *wl_display; struct wlr_compositor *compositor; struct wlr_seat *seat; - struct wl_listener seat_destroy; + struct wlr_gtk_primary_selection_device_manager *gtk_primary_selection; struct { struct wl_signal ready; struct wl_signal new_surface; } events; + struct wl_listener seat_destroy; + /** * Add a custom event handler to xwayland. Return 1 if the event was * handled or 0 to use the default wlr-xwayland handler. wlr-xwayland will @@ -223,6 +226,10 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); +void wlr_xwayland_set_gtk_primary_selection_device_manager( + struct wlr_xwayland *xwayland, + struct wlr_gtk_primary_selection_device_manager *manager); + bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface); struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( diff --git a/rootston/desktop.c b/rootston/desktop.c index 65a3509a..dc5caad9 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -955,11 +955,18 @@ struct roots_desktop *desktop_create(struct roots_server *server, wlr_server_decoration_manager_set_default_mode( desktop->server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); - desktop->primary_selection_device_manager = - wlr_gtk_primary_selection_device_manager_create(server->wl_display); desktop->idle = wlr_idle_create(server->wl_display); desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display); + desktop->primary_selection_device_manager = + wlr_gtk_primary_selection_device_manager_create(server->wl_display); +#if WLR_HAS_XWAYLAND + if (desktop->xwayland != NULL) { + wlr_xwayland_set_gtk_primary_selection_device_manager( + desktop->xwayland, desktop->primary_selection_device_manager); + } +#endif + desktop->input_inhibit = wlr_input_inhibit_manager_create(server->wl_display); desktop->input_inhibit_activate.notify = input_inhibit_activate; diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 537a3bae..360f5c30 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include "types/wlr_seat.h" @@ -88,10 +87,6 @@ static void seat_client_handle_resource_destroy( wl_resource_for_each_safe(resource, tmp, &client->data_devices) { wl_resource_destroy(resource); } - wl_resource_for_each_safe(resource, tmp, - &client->primary_selection_devices) { - wl_resource_destroy(resource); - } wl_list_remove(&client->link); free(client); @@ -138,7 +133,6 @@ static void seat_handle_bind(struct wl_client *client, void *_wlr_seat, wl_list_init(&seat_client->keyboards); wl_list_init(&seat_client->touches); wl_list_init(&seat_client->data_devices); - wl_list_init(&seat_client->primary_selection_devices); wl_signal_init(&seat_client->events.destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); @@ -167,11 +161,6 @@ void wlr_seat_destroy(struct wlr_seat *seat) { wlr_data_source_cancel(seat->selection_source); seat->selection_source = NULL; } - if (seat->primary_selection_source) { - wl_list_remove(&seat->primary_selection_source_destroy.link); - seat->primary_selection_source->cancel(seat->primary_selection_source); - seat->primary_selection_source = NULL; - } struct wlr_seat_client *client, *tmp; wl_list_for_each_safe(client, tmp, &seat->clients, link) { @@ -243,6 +232,8 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { seat->keyboard_state.seat = seat; wl_list_init(&seat->keyboard_state.surface_destroy.link); + wl_signal_init(&seat->keyboard_state.events.focus_change); + // touch state struct wlr_seat_touch_grab *touch_grab = calloc(1, sizeof(struct wlr_seat_touch_grab)); diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 1269c972..96176b6d 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -273,7 +273,6 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, wl_array_release(&keys); wlr_seat_client_send_selection(client); - wlr_seat_client_send_gtk_primary_selection(client); } // reinitialize the focus destroy events @@ -294,6 +293,13 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, // as it targets seat->keyboard_state.focused_client wlr_seat_keyboard_send_modifiers(seat, modifiers); } + + struct wlr_seat_keyboard_focus_change_event event = { + .seat = seat, + .old_surface = focused_surface, + .new_surface = surface, + }; + wlr_signal_emit_safe(&seat->keyboard_state.events.focus_change, &event); } void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat, diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index 5493a8c0..ccd931ae 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -22,7 +22,8 @@ static struct wlr_gtk_primary_selection_offer *offer_from_resource( static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_gtk_primary_selection_offer *offer = offer_from_resource(resource); + struct wlr_gtk_primary_selection_offer *offer = + offer_from_resource(resource); if (offer == NULL) { close(fd); return; @@ -52,7 +53,8 @@ static void offer_destroy(struct wlr_gtk_primary_selection_offer *offer) { } static void offer_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_gtk_primary_selection_offer *offer = offer_from_resource(resource); + struct wlr_gtk_primary_selection_offer *offer = + offer_from_resource(resource); offer_destroy(offer); } @@ -63,27 +65,8 @@ static void offer_handle_source_destroy(struct wl_listener *listener, offer_destroy(offer); } - -struct client_data_source { - struct wlr_gtk_primary_selection_source source; - struct wl_resource *resource; -}; - -static void client_source_send(struct wlr_gtk_primary_selection_source *wlr_source, - const char *mime_type, int32_t fd) { - struct client_data_source *source = (struct client_data_source *)wlr_source; - gtk_primary_selection_source_send_send(source->resource, mime_type, fd); - close(fd); -} - -static void client_source_cancel( - struct wlr_gtk_primary_selection_source *wlr_source) { - struct client_data_source *source = (struct client_data_source *)wlr_source; - gtk_primary_selection_source_send_cancelled(source->resource); -} - -static void source_send_offer(struct wlr_gtk_primary_selection_source *source, - struct wl_resource *device_resource) { +static void offer_create(struct wl_resource *device_resource, + struct wlr_gtk_primary_selection_source *source) { struct wlr_gtk_primary_selection_offer *offer = calloc(1, sizeof(struct wlr_gtk_primary_selection_offer)); if (offer == NULL) { @@ -103,6 +86,8 @@ static void source_send_offer(struct wlr_gtk_primary_selection_source *source, wl_resource_set_implementation(offer->resource, &offer_impl, offer, offer_handle_resource_destroy); + offer->source = source; + offer->source_destroy.notify = offer_handle_source_destroy; wl_signal_add(&source->events.destroy, &offer->source_destroy); @@ -114,12 +99,31 @@ static void source_send_offer(struct wlr_gtk_primary_selection_source *source, gtk_primary_selection_offer_send_offer(offer->resource, *p); } - offer->source = source; - gtk_primary_selection_device_send_selection(device_resource, offer->resource); } + +struct client_data_source { + struct wlr_gtk_primary_selection_source source; + struct wl_resource *resource; +}; + +static void client_source_send( + struct wlr_gtk_primary_selection_source *wlr_source, + const char *mime_type, int32_t fd) { + struct client_data_source *source = (struct client_data_source *)wlr_source; + gtk_primary_selection_source_send_send(source->resource, mime_type, fd); + close(fd); +} + +static void client_source_cancel( + struct wlr_gtk_primary_selection_source *wlr_source) { + struct client_data_source *source = (struct client_data_source *)wlr_source; + gtk_primary_selection_source_send_cancelled(source->resource); + // TODO: make the source resource inert +} + static const struct gtk_primary_selection_source_interface source_impl; static struct client_data_source *client_data_source_from_resource( @@ -164,84 +168,9 @@ static void source_resource_handle_destroy(struct wl_resource *resource) { } -void wlr_seat_client_send_gtk_primary_selection( - struct wlr_seat_client *seat_client) { - if (wl_list_empty(&seat_client->primary_selection_devices)) { - return; - } - - struct wlr_gtk_primary_selection_source *source = - seat_client->seat->primary_selection_source; - struct wl_resource *resource; - wl_resource_for_each(resource, &seat_client->primary_selection_devices) { - if (source) { - source_send_offer(source, resource); - } else { - gtk_primary_selection_device_send_selection(resource, NULL); - } - } -} - -static void seat_client_primary_selection_source_destroy( - struct wl_listener *listener, void *data) { - struct wlr_seat *seat = - wl_container_of(listener, seat, primary_selection_source_destroy); - struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client; - - if (seat_client && seat->keyboard_state.focused_surface) { - struct wl_resource *resource; - wl_resource_for_each(resource, &seat_client->primary_selection_devices) { - gtk_primary_selection_device_send_selection(resource, NULL); - } - } - - seat->primary_selection_source = NULL; - - wlr_signal_emit_safe(&seat->events.primary_selection, seat); -} - -void wlr_seat_set_gtk_primary_selection(struct wlr_seat *seat, - struct wlr_gtk_primary_selection_source *source, uint32_t serial) { - if (source) { - assert(source->send); - assert(source->cancel); - } - - if (seat->primary_selection_source && - seat->primary_selection_serial - serial < UINT32_MAX / 2) { - return; - } - - // TODO: make all offers inert - if (seat->primary_selection_source) { - wl_list_remove(&seat->primary_selection_source_destroy.link); - seat->primary_selection_source->cancel(seat->primary_selection_source); - seat->primary_selection_source = NULL; - } - - seat->primary_selection_source = source; - seat->primary_selection_serial = serial; - - struct wlr_seat_client *focused_client = - seat->keyboard_state.focused_client; - if (focused_client) { - wlr_seat_client_send_gtk_primary_selection(focused_client); - } - - wlr_signal_emit_safe(&seat->events.primary_selection, seat); - - if (source) { - seat->primary_selection_source_destroy.notify = - seat_client_primary_selection_source_destroy; - wl_signal_add(&source->events.destroy, - &seat->primary_selection_source_destroy); - } -} - - static const struct gtk_primary_selection_device_interface device_impl; -static struct wlr_seat_client *seat_client_from_device_resource( +static struct wlr_gtk_primary_selection_device *device_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, >k_primary_selection_device_interface, &device_impl)); @@ -251,17 +180,27 @@ static struct wlr_seat_client *seat_client_from_device_resource( static void device_handle_set_selection(struct wl_client *client, struct wl_resource *resource, struct wl_resource *source_resource, uint32_t serial) { + struct wlr_gtk_primary_selection_device *device = + device_from_resource(resource); + if (device == NULL) { + return; + } + struct client_data_source *source = NULL; if (source_resource != NULL) { source = client_data_source_from_resource(source_resource); } - struct wlr_seat_client *seat_client = - seat_client_from_device_resource(resource); + // TODO: improve serial checking + struct wlr_seat *seat = device->seat; + if (seat->primary_selection_serial > 0 && + seat->primary_selection_serial - serial < UINT32_MAX / 2) { + return; + } + seat->primary_selection_serial = serial; - struct wlr_gtk_primary_selection_source *wlr_source = - (struct wlr_gtk_primary_selection_source *)source; - wlr_seat_set_gtk_primary_selection(seat_client->seat, wlr_source, serial); + wlr_gtk_primary_selection_device_manager_set_selection(device->manager, + seat, &source->source); } static void device_handle_destroy(struct wl_client *client, @@ -274,11 +213,162 @@ static const struct gtk_primary_selection_device_interface device_impl = { .destroy = device_handle_destroy, }; -static void device_resource_handle_destroy(struct wl_resource *resource) { +static void device_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); } +static void device_resource_send_selection(struct wl_resource *resource, + struct wlr_gtk_primary_selection_source *source) { + assert(device_from_resource(resource) != NULL); + + if (source != NULL) { + offer_create(resource, source); + } else { + gtk_primary_selection_device_send_selection(resource, NULL); + } +} + +static void device_send_selection( + struct wlr_gtk_primary_selection_device *device) { + struct wlr_seat_client *seat_client = + device->seat->keyboard_state.focused_client; + + struct wl_resource *resource; + wl_resource_for_each(resource, &device->resources) { + if (wl_resource_get_client(resource) == seat_client->client) { + device_resource_send_selection(resource, device->source); + } + } +} + +static void device_handle_source_destroy(struct wl_listener *listener, + void *data); + +static void device_set_selection( + struct wlr_gtk_primary_selection_device *device, + struct wlr_gtk_primary_selection_source *source) { + if (source != NULL) { + assert(source->send); + assert(source->cancel); + } + + if (device->source != NULL) { + wl_list_remove(&device->source_destroy.link); + device->source->cancel(device->source); + device->source = NULL; + } + + struct wlr_gtk_primary_selection_offer *offer, *tmp; + wl_list_for_each_safe(offer, tmp, &device->offers, link) { + offer_destroy(offer); + } + + device->source = source; + if (source != NULL) { + device->source_destroy.notify = device_handle_source_destroy; + wl_signal_add(&source->events.destroy, &device->source_destroy); + } + + device_send_selection(device); + + struct wlr_seat *seat = device->seat; + // TODO: remove these from wlr_seat + seat->primary_selection_source = source; + wlr_signal_emit_safe(&seat->events.primary_selection, seat); +} + +static void device_destroy(struct wlr_gtk_primary_selection_device *device); + +static void device_handle_seat_destroy(struct wl_listener *listener, + void *data) { + struct wlr_gtk_primary_selection_device *device = + wl_container_of(listener, device, seat_destroy); + device_destroy(device); +} + +static void device_handle_seat_focus_change(struct wl_listener *listener, + void *data) { + struct wlr_gtk_primary_selection_device *device = + wl_container_of(listener, device, seat_focus_change); + device_send_selection(device); +} + +static void device_handle_source_destroy(struct wl_listener *listener, + void *data) { + struct wlr_gtk_primary_selection_device *device = + wl_container_of(listener, device, source_destroy); + wl_list_remove(&device->source_destroy.link); + device->source = NULL; + device_send_selection(device); +} + +static struct wlr_gtk_primary_selection_device *get_or_create_device( + struct wlr_gtk_primary_selection_device_manager *manager, + struct wlr_seat *seat) { + struct wlr_gtk_primary_selection_device *device; + wl_list_for_each(device, &manager->devices, link) { + if (device->seat == seat) { + return device; + } + } + + device = calloc(1, sizeof(struct wlr_gtk_primary_selection_device)); + if (device == NULL) { + return NULL; + } + device->manager = manager; + device->seat = seat; + + wl_list_init(&device->resources); + wl_list_insert(&manager->devices, &device->link); + + wl_list_init(&device->offers); + + device->seat_destroy.notify = device_handle_seat_destroy; + wl_signal_add(&seat->events.destroy, &device->seat_destroy); + + device->seat_focus_change.notify = device_handle_seat_focus_change; + wl_signal_add(&seat->keyboard_state.events.focus_change, + &device->seat_focus_change); + + return device; +} + +static void device_destroy(struct wlr_gtk_primary_selection_device *device) { + if (device == NULL) { + return; + } + wl_list_remove(&device->link); + wl_list_remove(&device->seat_destroy.link); + wl_list_remove(&device->seat_focus_change.link); + struct wlr_gtk_primary_selection_offer *offer, *offer_tmp; + wl_list_for_each_safe(offer, offer_tmp, &device->offers, link) { + offer_destroy(offer); + } + struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &device->resources) { + // Make the resource inert + wl_resource_set_user_data(resource, NULL); + + struct wl_list *link = wl_resource_get_link(resource); + wl_list_remove(link); + wl_list_init(link); + } + free(device); +} + + +static const struct gtk_primary_selection_device_manager_interface + device_manager_impl; + +struct wlr_gtk_primary_selection_device_manager *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + >k_primary_selection_device_manager_interface, &device_manager_impl)); + return wl_resource_get_user_data(resource); +} + void wlr_gtk_primary_selection_source_init( struct wlr_gtk_primary_selection_source *source) { wl_array_init(&source->mime_types); @@ -310,7 +400,7 @@ static void device_manager_handle_create_source(struct wl_client *client, } wlr_gtk_primary_selection_source_init(&source->source); - int version = wl_resource_get_version(manager_resource); + uint32_t version = wl_resource_get_version(manager_resource); source->resource = wl_resource_create(client, >k_primary_selection_source_interface, version, id); if (source->resource == NULL) { @@ -330,6 +420,15 @@ void device_manager_handle_get_device(struct wl_client *client, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); + struct wlr_gtk_primary_selection_device_manager *manager = + manager_from_resource(manager_resource); + + struct wlr_gtk_primary_selection_device *device = + get_or_create_device(manager, seat_client->seat); + if (device == NULL) { + wl_resource_post_no_memory(manager_resource); + return; + } uint32_t version = wl_resource_get_version(manager_resource); struct wl_resource *resource = wl_resource_create(client, @@ -338,10 +437,13 @@ void device_manager_handle_get_device(struct wl_client *client, wl_resource_post_no_memory(manager_resource); return; } - wl_resource_set_implementation(resource, &device_impl, seat_client, - &device_resource_handle_destroy); - wl_list_insert(&seat_client->primary_selection_devices, - wl_resource_get_link(resource)); + wl_resource_set_implementation(resource, &device_impl, device, + device_handle_resource_destroy); + wl_list_insert(&device->resources, wl_resource_get_link(resource)); + + if (device->seat->keyboard_state.focused_client == seat_client) { + device_resource_send_selection(resource, device->source); + } } static void device_manager_handle_destroy(struct wl_client *client, @@ -362,6 +464,18 @@ static void device_manager_handle_resource_destroy( } +void wlr_gtk_primary_selection_device_manager_set_selection( + struct wlr_gtk_primary_selection_device_manager *manager, + struct wlr_seat *seat, + struct wlr_gtk_primary_selection_source *source) { + struct wlr_gtk_primary_selection_device *device = + get_or_create_device(manager, seat); + if (device == NULL) { + return; + } + device_set_selection(device, source); +} + static void primary_selection_device_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wlr_gtk_primary_selection_device_manager *manager = data; @@ -401,6 +515,7 @@ struct wlr_gtk_primary_selection_device_manager * } wl_list_init(&manager->resources); + wl_list_init(&manager->devices); wl_signal_init(&manager->events.destroy); manager->display_destroy.notify = handle_display_destroy; diff --git a/xwayland/selection/incoming.c b/xwayland/selection/incoming.c index d4d7d553..0fe759a0 100644 --- a/xwayland/selection/incoming.c +++ b/xwayland/selection/incoming.c @@ -365,9 +365,9 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { bool ok = source_get_targets(selection, &source->base.mime_types, &source->mime_types_atoms); - if (ok) { - wlr_seat_set_gtk_primary_selection(xwm->seat, &source->base, - wl_display_next_serial(xwm->xwayland->wl_display)); + if (ok && xwm->xwayland->gtk_primary_selection) { + wlr_gtk_primary_selection_device_manager_set_selection( + xwm->xwayland->gtk_primary_selection, xwm->seat, &source->base); } else { source->base.cancel(&source->base); } @@ -423,9 +423,10 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, if (selection == &xwm->clipboard_selection) { wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); - } else if (selection == &xwm->primary_selection) { - wlr_seat_set_gtk_primary_selection(xwm->seat, NULL, - wl_display_next_serial(xwm->xwayland->wl_display)); + } else if (selection == &xwm->primary_selection && + xwm->xwayland->gtk_primary_selection) { + wlr_gtk_primary_selection_device_manager_set_selection( + xwm->xwayland->gtk_primary_selection, xwm->seat, NULL); } else if (selection == &xwm->dnd_selection) { // TODO: DND } else { diff --git a/xwayland/selection/selection.c b/xwayland/selection/selection.c index a29eeeae..db6246bf 100644 --- a/xwayland/selection/selection.c +++ b/xwayland/selection/selection.c @@ -228,11 +228,12 @@ void xwm_selection_finish(struct wlr_xwm *xwm) { wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); } - if (xwm->seat->primary_selection_source && + if (xwm->xwayland->gtk_primary_selection && + xwm->seat->primary_selection_source && primary_selection_source_is_xwayland( xwm->seat->primary_selection_source)) { - wlr_seat_set_gtk_primary_selection(xwm->seat, NULL, - wl_display_next_serial(xwm->xwayland->wl_display)); + wlr_gtk_primary_selection_device_manager_set_selection( + xwm->xwayland->gtk_primary_selection, xwm->seat, NULL); } wlr_xwayland_set_seat(xwm->xwayland, NULL); } diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index e6d3502c..bbdee1a7 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -505,3 +505,9 @@ void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, xwayland->seat_destroy.notify = xwayland_handle_seat_destroy; wl_signal_add(&seat->events.destroy, &xwayland->seat_destroy); } + +void wlr_xwayland_set_gtk_primary_selection_device_manager( + struct wlr_xwayland *xwayland, + struct wlr_gtk_primary_selection_device_manager *manager) { + xwayland->gtk_primary_selection = manager; +} From cbe42d100644307af92f71a04b68a005c31c62d6 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 27 Nov 2018 19:45:39 +0100 Subject: [PATCH 2/5] gtk-primary-selection: remove offer struct We don't need it, we can use the device instead. --- include/wlr/types/wlr_gtk_primary_selection.h | 17 +-- include/wlr/types/wlr_seat.h | 1 - types/wlr_gtk_primary_selection.c | 101 ++++++++---------- 3 files changed, 45 insertions(+), 74 deletions(-) diff --git a/include/wlr/types/wlr_gtk_primary_selection.h b/include/wlr/types/wlr_gtk_primary_selection.h index e2019123..ed025869 100644 --- a/include/wlr/types/wlr_gtk_primary_selection.h +++ b/include/wlr/types/wlr_gtk_primary_selection.h @@ -36,7 +36,7 @@ struct wlr_gtk_primary_selection_device { struct wl_list resources; // wl_resource_get_link struct wlr_gtk_primary_selection_source *source; - struct wl_list offers; // wlr_gtk_primary_selection_offer::link + struct wl_list offers; // wl_resource_get_link struct wl_listener seat_destroy; struct wl_listener seat_focus_change; @@ -64,21 +64,6 @@ struct wlr_gtk_primary_selection_source { void *data; }; -/** - * An offer is the receiving side of a selection. When the selection is set, - * offers are created for the currently focused client and can be used to - * initiate the data transfer. - */ -struct wlr_gtk_primary_selection_offer { - struct wl_resource *resource; - struct wlr_gtk_primary_selection_source *source; - struct wl_list link; // wlr_gtk_primary_selection_device::offers - - struct wl_listener source_destroy; - - void *data; -}; - struct wlr_gtk_primary_selection_device_manager * wlr_gtk_primary_selection_device_manager_create(struct wl_display *display); void wlr_gtk_primary_selection_device_manager_destroy( diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index f064c3bb..0b8f15ab 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -199,7 +199,6 @@ struct wlr_seat { // not owned by the seat struct wlr_gtk_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; diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index ccd931ae..9a8848d6 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -13,7 +13,7 @@ static const struct gtk_primary_selection_offer_interface offer_impl; -static struct wlr_gtk_primary_selection_offer *offer_from_resource( +static struct wlr_gtk_primary_selection_device *device_from_offer_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, >k_primary_selection_offer_interface, &offer_impl)); @@ -22,14 +22,14 @@ static struct wlr_gtk_primary_selection_offer *offer_from_resource( static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct wlr_gtk_primary_selection_offer *offer = - offer_from_resource(resource); - if (offer == NULL) { + struct wlr_gtk_primary_selection_device *device = + device_from_offer_resource(resource); + if (device == NULL || device->source == NULL) { close(fd); return; } - offer->source->send(offer->source, mime_type, fd); + device->source->send(device->source, mime_type, fd); } static void offer_handle_destroy(struct wl_client *client, @@ -42,65 +42,53 @@ static const struct gtk_primary_selection_offer_interface offer_impl = { .destroy = offer_handle_destroy, }; -static void offer_destroy(struct wlr_gtk_primary_selection_offer *offer) { - if (offer == NULL) { - return; - } - // Make resource inert - wl_resource_set_user_data(offer->resource, NULL); - wl_list_remove(&offer->source_destroy.link); - free(offer); -} - static void offer_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_gtk_primary_selection_offer *offer = - offer_from_resource(resource); - offer_destroy(offer); + wl_list_remove(wl_resource_get_link(resource)); } -static void offer_handle_source_destroy(struct wl_listener *listener, - void *data) { - struct wlr_gtk_primary_selection_offer *offer = - wl_container_of(listener, offer, source_destroy); - offer_destroy(offer); -} +static struct wlr_gtk_primary_selection_device *device_from_resource( + struct wl_resource *resource); -static void offer_create(struct wl_resource *device_resource, +static void create_offer(struct wl_resource *device_resource, struct wlr_gtk_primary_selection_source *source) { - struct wlr_gtk_primary_selection_offer *offer = - calloc(1, sizeof(struct wlr_gtk_primary_selection_offer)); - if (offer == NULL) { - wl_resource_post_no_memory(device_resource); - return; - } + struct wlr_gtk_primary_selection_device *device = + device_from_resource(device_resource); + assert(device != NULL); struct wl_client *client = wl_resource_get_client(device_resource); uint32_t version = wl_resource_get_version(device_resource); - offer->resource = wl_resource_create(client, + struct wl_resource *resource = wl_resource_create(client, >k_primary_selection_offer_interface, version, 0); - if (offer->resource == NULL) { - free(offer); + if (resource == NULL) { wl_resource_post_no_memory(device_resource); return; } - wl_resource_set_implementation(offer->resource, &offer_impl, offer, + wl_resource_set_implementation(resource, &offer_impl, device, offer_handle_resource_destroy); - offer->source = source; + wl_list_insert(&device->offers, wl_resource_get_link(resource)); - offer->source_destroy.notify = offer_handle_source_destroy; - wl_signal_add(&source->events.destroy, &offer->source_destroy); - - gtk_primary_selection_device_send_data_offer(device_resource, - offer->resource); + gtk_primary_selection_device_send_data_offer(device_resource, resource); char **p; wl_array_for_each(p, &source->mime_types) { - gtk_primary_selection_offer_send_offer(offer->resource, *p); + gtk_primary_selection_offer_send_offer(resource, *p); } - gtk_primary_selection_device_send_selection(device_resource, - offer->resource); + gtk_primary_selection_device_send_selection(device_resource, resource); +} + +static void destroy_offer(struct wl_resource *resource) { + if (device_from_offer_resource(resource) == NULL) { + return; + } + + // Make the offer inert + wl_resource_set_user_data(resource, NULL); + + struct wl_list *link = wl_resource_get_link(resource); + wl_list_remove(link); + wl_list_init(link); } @@ -193,12 +181,6 @@ static void device_handle_set_selection(struct wl_client *client, // TODO: improve serial checking struct wlr_seat *seat = device->seat; - if (seat->primary_selection_serial > 0 && - seat->primary_selection_serial - serial < UINT32_MAX / 2) { - return; - } - seat->primary_selection_serial = serial; - wlr_gtk_primary_selection_device_manager_set_selection(device->manager, seat, &source->source); } @@ -223,7 +205,7 @@ static void device_resource_send_selection(struct wl_resource *resource, assert(device_from_resource(resource) != NULL); if (source != NULL) { - offer_create(resource, source); + create_offer(resource, source); } else { gtk_primary_selection_device_send_selection(resource, NULL); } @@ -259,9 +241,9 @@ static void device_set_selection( device->source = NULL; } - struct wlr_gtk_primary_selection_offer *offer, *tmp; - wl_list_for_each_safe(offer, tmp, &device->offers, link) { - offer_destroy(offer); + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &device->offers) { + destroy_offer(resource); } device->source = source; @@ -291,6 +273,8 @@ static void device_handle_seat_focus_change(struct wl_listener *listener, void *data) { struct wlr_gtk_primary_selection_device *device = wl_container_of(listener, device, seat_focus_change); + // TODO: maybe make previous offers inert, or set a NULL selection for + // previous client? device_send_selection(device); } @@ -342,11 +326,14 @@ static void device_destroy(struct wlr_gtk_primary_selection_device *device) { wl_list_remove(&device->link); wl_list_remove(&device->seat_destroy.link); wl_list_remove(&device->seat_focus_change.link); - struct wlr_gtk_primary_selection_offer *offer, *offer_tmp; - wl_list_for_each_safe(offer, offer_tmp, &device->offers, link) { - offer_destroy(offer); + if (device->source != NULL) { + wl_list_remove(&device->source_destroy.link); + device->source->cancel(device->source); } struct wl_resource *resource, *resource_tmp; + wl_resource_for_each_safe(resource, resource_tmp, &device->offers) { + destroy_offer(resource); + } wl_resource_for_each_safe(resource, resource_tmp, &device->resources) { // Make the resource inert wl_resource_set_user_data(resource, NULL); From bfa7f4ee0dd5988ea54795862a12a1eb1680b3f7 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 27 Nov 2018 20:16:55 +0100 Subject: [PATCH 3/5] gtk-primary-selection: use impl pattern for sources --- include/wlr/types/wlr_gtk_primary_selection.h | 24 ++-- types/wlr_gtk_primary_selection.c | 107 +++++++++++------- xwayland/selection/incoming.c | 28 +++-- xwayland/selection/outgoing.c | 2 +- 4 files changed, 100 insertions(+), 61 deletions(-) diff --git a/include/wlr/types/wlr_gtk_primary_selection.h b/include/wlr/types/wlr_gtk_primary_selection.h index ed025869..cbf29088 100644 --- a/include/wlr/types/wlr_gtk_primary_selection.h +++ b/include/wlr/types/wlr_gtk_primary_selection.h @@ -45,18 +45,24 @@ struct wlr_gtk_primary_selection_device { void *data; }; +/** + * A data source implementation. Only the `send` function is mandatory. + */ +struct wlr_gtk_primary_selection_source_impl { + void (*send)(struct wlr_gtk_primary_selection_source *source, + const char *mime_type, int fd); + void (*destroy)(struct wlr_gtk_primary_selection_source *source); +}; + /** * A source is the sending side of a selection. */ struct wlr_gtk_primary_selection_source { + const struct wlr_gtk_primary_selection_source_impl *impl; + // source metadata struct wl_array mime_types; - // source implementation - void (*send)(struct wlr_gtk_primary_selection_source *source, - const char *mime_type, int32_t fd); - void (*cancel)(struct wlr_gtk_primary_selection_source *source); - struct { struct wl_signal destroy; } events; @@ -75,8 +81,12 @@ void wlr_gtk_primary_selection_device_manager_set_selection( struct wlr_gtk_primary_selection_source *source); void wlr_gtk_primary_selection_source_init( + struct wlr_gtk_primary_selection_source *source, + const struct wlr_gtk_primary_selection_source_impl *impl); +void wlr_gtk_primary_selection_source_destroy( struct wlr_gtk_primary_selection_source *source); -void wlr_gtk_primary_selection_source_finish( - struct wlr_gtk_primary_selection_source *source); +void wlr_gtk_primary_selection_source_send( + struct wlr_gtk_primary_selection_source *source, const char *mime_type, + int fd); #endif diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index 9a8848d6..5a31d242 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -29,7 +29,7 @@ static void offer_handle_receive(struct wl_client *client, return; } - device->source->send(device->source, mime_type, fd); + wlr_gtk_primary_selection_source_send(device->source, mime_type, fd); } static void offer_handle_destroy(struct wl_client *client, @@ -99,19 +99,26 @@ struct client_data_source { static void client_source_send( struct wlr_gtk_primary_selection_source *wlr_source, - const char *mime_type, int32_t fd) { + const char *mime_type, int fd) { struct client_data_source *source = (struct client_data_source *)wlr_source; gtk_primary_selection_source_send_send(source->resource, mime_type, fd); close(fd); } -static void client_source_cancel( +static void client_source_destroy( struct wlr_gtk_primary_selection_source *wlr_source) { struct client_data_source *source = (struct client_data_source *)wlr_source; gtk_primary_selection_source_send_cancelled(source->resource); - // TODO: make the source resource inert + // Make the source resource inert + wl_resource_set_user_data(source->resource, NULL); + free(source); } +static const struct wlr_gtk_primary_selection_source_impl client_source_impl = { + .send = client_source_send, + .destroy = client_source_destroy, +}; + static const struct gtk_primary_selection_source_interface source_impl; static struct client_data_source *client_data_source_from_resource( @@ -125,6 +132,9 @@ static void source_handle_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { struct client_data_source *source = client_data_source_from_resource(resource); + if (source == NULL) { + return; + } char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); if (p) { @@ -151,8 +161,10 @@ static const struct gtk_primary_selection_source_interface source_impl = { static void source_resource_handle_destroy(struct wl_resource *resource) { struct client_data_source *source = client_data_source_from_resource(resource); - wlr_gtk_primary_selection_source_finish(&source->source); - free(source); + if (source == NULL) { + return; + } + wlr_gtk_primary_selection_source_destroy(&source->source); } @@ -174,15 +186,20 @@ static void device_handle_set_selection(struct wl_client *client, return; } - struct client_data_source *source = NULL; + struct client_data_source *client_source = NULL; if (source_resource != NULL) { - source = client_data_source_from_resource(source_resource); + client_source = client_data_source_from_resource(source_resource); + } + + struct wlr_gtk_primary_selection_source *source = NULL; + if (client_source != NULL) { + source = &client_source->source; } // TODO: improve serial checking struct wlr_seat *seat = device->seat; wlr_gtk_primary_selection_device_manager_set_selection(device->manager, - seat, &source->source); + seat, source); } static void device_handle_destroy(struct wl_client *client, @@ -230,14 +247,9 @@ static void device_handle_source_destroy(struct wl_listener *listener, static void device_set_selection( struct wlr_gtk_primary_selection_device *device, struct wlr_gtk_primary_selection_source *source) { - if (source != NULL) { - assert(source->send); - assert(source->cancel); - } - if (device->source != NULL) { wl_list_remove(&device->source_destroy.link); - device->source->cancel(device->source); + wlr_gtk_primary_selection_source_destroy(device->source); device->source = NULL; } @@ -328,7 +340,7 @@ static void device_destroy(struct wlr_gtk_primary_selection_device *device) { wl_list_remove(&device->seat_focus_change.link); if (device->source != NULL) { wl_list_remove(&device->source_destroy.link); - device->source->cancel(device->source); + wlr_gtk_primary_selection_source_destroy(device->source); } struct wl_resource *resource, *resource_tmp; wl_resource_for_each_safe(resource, resource_tmp, &device->offers) { @@ -356,27 +368,6 @@ struct wlr_gtk_primary_selection_device_manager *manager_from_resource( return wl_resource_get_user_data(resource); } -void wlr_gtk_primary_selection_source_init( - struct wlr_gtk_primary_selection_source *source) { - wl_array_init(&source->mime_types); - wl_signal_init(&source->events.destroy); -} - -void wlr_gtk_primary_selection_source_finish( - struct wlr_gtk_primary_selection_source *source) { - if (source == NULL) { - return; - } - - wlr_signal_emit_safe(&source->events.destroy, source); - - char **p; - wl_array_for_each(p, &source->mime_types) { - free(*p); - } - wl_array_release(&source->mime_types); -} - static void device_manager_handle_create_source(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id) { struct client_data_source *source = @@ -385,7 +376,7 @@ static void device_manager_handle_create_source(struct wl_client *client, wl_client_post_no_memory(client); return; } - wlr_gtk_primary_selection_source_init(&source->source); + wlr_gtk_primary_selection_source_init(&source->source, &client_source_impl); uint32_t version = wl_resource_get_version(manager_resource); source->resource = wl_resource_create(client, @@ -397,9 +388,6 @@ static void device_manager_handle_create_source(struct wl_client *client, } wl_resource_set_implementation(source->resource, &source_impl, source, source_resource_handle_destroy); - - source->source.send = client_source_send; - source->source.cancel = client_source_cancel; } void device_manager_handle_get_device(struct wl_client *client, @@ -525,3 +513,40 @@ void wlr_gtk_primary_selection_device_manager_destroy( wl_global_destroy(manager->global); free(manager); } + + +void wlr_gtk_primary_selection_source_init( + struct wlr_gtk_primary_selection_source *source, + const struct wlr_gtk_primary_selection_source_impl *impl) { + assert(impl->send); + wl_array_init(&source->mime_types); + wl_signal_init(&source->events.destroy); + source->impl = impl; +} + +void wlr_gtk_primary_selection_source_destroy( + struct wlr_gtk_primary_selection_source *source) { + if (source == NULL) { + return; + } + + wlr_signal_emit_safe(&source->events.destroy, source); + + char **p; + wl_array_for_each(p, &source->mime_types) { + free(*p); + } + wl_array_release(&source->mime_types); + + if (source->impl->destroy) { + source->impl->destroy(source); + } else { + free(source); + } +} + +void wlr_gtk_primary_selection_source_send( + struct wlr_gtk_primary_selection_source *source, const char *mime_type, + int32_t fd) { + source->impl->send(source, mime_type, fd); +} diff --git a/xwayland/selection/incoming.c b/xwayland/selection/incoming.c index 0fe759a0..3342a761 100644 --- a/xwayland/selection/incoming.c +++ b/xwayland/selection/incoming.c @@ -137,7 +137,7 @@ static void xwm_selection_get_data(struct wlr_xwm_selection *selection) { static void source_send(struct wlr_xwm_selection *selection, struct wl_array *mime_types, struct wl_array *mime_types_atoms, - const char *requested_mime_type, int32_t fd) { + const char *requested_mime_type, int fd) { struct wlr_xwm *xwm = selection->xwm; struct wlr_xwm_selection_transfer *transfer = &selection->incoming; @@ -222,17 +222,17 @@ struct x11_primary_selection_source { struct wl_array mime_types_atoms; }; -static void primary_selection_source_cancel( - struct wlr_gtk_primary_selection_source *wlr_source); +static const struct wlr_gtk_primary_selection_source_impl + primary_selection_source_impl; bool primary_selection_source_is_xwayland( struct wlr_gtk_primary_selection_source *wlr_source) { - return wlr_source->cancel == primary_selection_source_cancel; + return wlr_source->impl == &primary_selection_source_impl; } static void primary_selection_source_send( - struct wlr_gtk_primary_selection_source *wlr_source, const char *mime_type, - int32_t fd) { + struct wlr_gtk_primary_selection_source *wlr_source, + const char *mime_type, int fd) { struct x11_primary_selection_source *source = (struct x11_primary_selection_source *)wlr_source; struct wlr_xwm_selection *selection = source->selection; @@ -241,15 +241,20 @@ static void primary_selection_source_send( mime_type, fd); } -static void primary_selection_source_cancel( +static void primary_selection_source_destroy( struct wlr_gtk_primary_selection_source *wlr_source) { struct x11_primary_selection_source *source = (struct x11_primary_selection_source *)wlr_source; - wlr_gtk_primary_selection_source_finish(&source->base); wl_array_release(&source->mime_types_atoms); free(source); } +static const struct wlr_gtk_primary_selection_source_impl + primary_selection_source_impl = { + .send = primary_selection_source_send, + .destroy = primary_selection_source_destroy, +}; + static bool source_get_targets(struct wlr_xwm_selection *selection, struct wl_array *mime_types, struct wl_array *mime_types_atoms) { struct wlr_xwm *xwm = selection->xwm; @@ -356,9 +361,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { if (source == NULL) { return; } - wlr_gtk_primary_selection_source_init(&source->base); - source->base.send = primary_selection_source_send; - source->base.cancel = primary_selection_source_cancel; + wlr_gtk_primary_selection_source_init(&source->base, + &primary_selection_source_impl); source->selection = selection; wl_array_init(&source->mime_types_atoms); @@ -369,7 +373,7 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { wlr_gtk_primary_selection_device_manager_set_selection( xwm->xwayland->gtk_primary_selection, xwm->seat, &source->base); } else { - source->base.cancel(&source->base); + wlr_gtk_primary_selection_source_destroy(&source->base); } } else if (selection == &xwm->dnd_selection) { // TODO diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index b658ab52..1c994e18 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -198,7 +198,7 @@ static void xwm_selection_source_send(struct wlr_xwm_selection *selection, struct wlr_gtk_primary_selection_source *source = selection->xwm->seat->primary_selection_source; if (source != NULL) { - source->send(source, mime_type, fd); + wlr_gtk_primary_selection_source_send(source, mime_type, fd); return; } } else if (selection == &selection->xwm->dnd_selection) { From 658b5905671ec229e44986e82af2666c40435d43 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 27 Nov 2018 21:09:41 +0100 Subject: [PATCH 4/5] gtk-primary-selection: fix segfault when no focus --- types/wlr_gtk_primary_selection.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index 5a31d242..ebf4e5e3 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -232,6 +232,9 @@ static void device_send_selection( struct wlr_gtk_primary_selection_device *device) { struct wlr_seat_client *seat_client = device->seat->keyboard_state.focused_client; + if (seat_client == NULL) { + return; + } struct wl_resource *resource; wl_resource_for_each(resource, &device->resources) { From 9f0720c03abcc600b6156b52e367d7cafcf57644 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 28 Nov 2018 16:37:35 +0100 Subject: [PATCH 5/5] primary-selection: introduce wlr_primary_selection_source This is a common interface that can be used for all primary selection protocols, as discussed in [1]. A new function wlr_seat_set_primary_selection is added to set the primary selection for all protocols. The seat now owns again the source, and resets the selection to NULL when destroyed. [1]: https://github.com/swaywm/wlroots/issues/1367#issuecomment-442403454 --- include/wlr/types/meson.build | 1 + include/wlr/types/wlr_gtk_primary_selection.h | 42 +---- include/wlr/types/wlr_primary_selection.h | 54 ++++++ include/wlr/types/wlr_seat.h | 6 +- include/wlr/xwayland.h | 5 - include/xwayland/selection.h | 4 +- rootston/desktop.c | 8 - types/meson.build | 3 +- types/seat/wlr_seat.c | 3 + types/wlr_gtk_primary_selection.c | 159 +++++------------- types/wlr_primary_selection.c | 69 ++++++++ xwayland/selection/incoming.c | 31 ++-- xwayland/selection/outgoing.c | 10 +- xwayland/selection/selection.c | 17 +- xwayland/xwayland.c | 6 - 15 files changed, 209 insertions(+), 209 deletions(-) create mode 100644 include/wlr/types/wlr_primary_selection.h create mode 100644 types/wlr_primary_selection.c diff --git a/include/wlr/types/meson.build b/include/wlr/types/meson.build index df611970..491d4a50 100644 --- a/include/wlr/types/meson.build +++ b/include/wlr/types/meson.build @@ -23,6 +23,7 @@ install_headers( 'wlr_output.h', 'wlr_pointer.h', 'wlr_presentation_time.h', + 'wlr_primary_selection.h', 'wlr_region.h', 'wlr_screencopy_v1.h', 'wlr_screenshooter.h', diff --git a/include/wlr/types/wlr_gtk_primary_selection.h b/include/wlr/types/wlr_gtk_primary_selection.h index cbf29088..7cf34201 100644 --- a/include/wlr/types/wlr_gtk_primary_selection.h +++ b/include/wlr/types/wlr_gtk_primary_selection.h @@ -35,37 +35,11 @@ struct wlr_gtk_primary_selection_device { struct wl_list link; // wlr_gtk_primary_selection_device_manager::devices struct wl_list resources; // wl_resource_get_link - struct wlr_gtk_primary_selection_source *source; struct wl_list offers; // wl_resource_get_link struct wl_listener seat_destroy; struct wl_listener seat_focus_change; - struct wl_listener source_destroy; - - void *data; -}; - -/** - * A data source implementation. Only the `send` function is mandatory. - */ -struct wlr_gtk_primary_selection_source_impl { - void (*send)(struct wlr_gtk_primary_selection_source *source, - const char *mime_type, int fd); - void (*destroy)(struct wlr_gtk_primary_selection_source *source); -}; - -/** - * A source is the sending side of a selection. - */ -struct wlr_gtk_primary_selection_source { - const struct wlr_gtk_primary_selection_source_impl *impl; - - // source metadata - struct wl_array mime_types; - - struct { - struct wl_signal destroy; - } events; + struct wl_listener seat_primary_selection; void *data; }; @@ -75,18 +49,4 @@ struct wlr_gtk_primary_selection_device_manager * void wlr_gtk_primary_selection_device_manager_destroy( struct wlr_gtk_primary_selection_device_manager *manager); -void wlr_gtk_primary_selection_device_manager_set_selection( - struct wlr_gtk_primary_selection_device_manager *manager, - struct wlr_seat *seat, - struct wlr_gtk_primary_selection_source *source); - -void wlr_gtk_primary_selection_source_init( - struct wlr_gtk_primary_selection_source *source, - const struct wlr_gtk_primary_selection_source_impl *impl); -void wlr_gtk_primary_selection_source_destroy( - struct wlr_gtk_primary_selection_source *source); -void wlr_gtk_primary_selection_source_send( - struct wlr_gtk_primary_selection_source *source, const char *mime_type, - int fd); - #endif diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h new file mode 100644 index 00000000..9be61acc --- /dev/null +++ b/include/wlr/types/wlr_primary_selection.h @@ -0,0 +1,54 @@ +/* + * This an unstable interface of wlroots. No guarantees are made regarding the + * future consistency of this API. + */ +#ifndef WLR_USE_UNSTABLE +#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" +#endif + +#ifndef WLR_TYPES_WLR_PRIMARY_SELECTION_H +#define WLR_TYPES_WLR_PRIMARY_SELECTION_H + +#include +#include + +struct wlr_primary_selection_source; + +/** + * A data source implementation. Only the `send` function is mandatory. + */ +struct wlr_primary_selection_source_impl { + void (*send)(struct wlr_primary_selection_source *source, + const char *mime_type, int fd); + void (*destroy)(struct wlr_primary_selection_source *source); +}; + +/** + * A source is the sending side of a selection. + */ +struct wlr_primary_selection_source { + const struct wlr_primary_selection_source_impl *impl; + + // source metadata + struct wl_array mime_types; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +void wlr_primary_selection_source_init( + struct wlr_primary_selection_source *source, + const struct wlr_primary_selection_source_impl *impl); +void wlr_primary_selection_source_destroy( + struct wlr_primary_selection_source *source); +void wlr_primary_selection_source_send( + struct wlr_primary_selection_source *source, const char *mime_type, + int fd); + +void wlr_seat_set_primary_selection(struct wlr_seat *seat, + struct wlr_primary_selection_source *source); + +#endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 0b8f15ab..942a3420 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -184,6 +184,8 @@ struct wlr_seat_touch_state { struct wlr_seat_touch_grab *default_grab; }; +struct wlr_primary_selection_source; + struct wlr_seat { struct wl_global *global; struct wl_display *display; @@ -197,8 +199,7 @@ struct wlr_seat { struct wlr_data_source *selection_source; uint32_t selection_serial; - // not owned by the seat - struct wlr_gtk_primary_selection_source *primary_selection_source; + struct wlr_primary_selection_source *primary_selection_source; // `drag` goes away before `drag_source`, when the implicit grab ends struct wlr_drag *drag; @@ -211,6 +212,7 @@ struct wlr_seat { struct wl_listener display_destroy; struct wl_listener selection_source_destroy; + struct wl_listener primary_selection_source_destroy; struct wl_listener drag_source_destroy; struct { diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index 9a7f0f07..40cc8848 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -43,7 +43,6 @@ struct wlr_xwayland { struct wl_display *wl_display; struct wlr_compositor *compositor; struct wlr_seat *seat; - struct wlr_gtk_primary_selection_device_manager *gtk_primary_selection; struct { struct wl_signal ready; @@ -226,10 +225,6 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); -void wlr_xwayland_set_gtk_primary_selection_device_manager( - struct wlr_xwayland *xwayland, - struct wlr_gtk_primary_selection_device_manager *manager); - bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface); struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( diff --git a/include/xwayland/selection.h b/include/xwayland/selection.h index 6529e9eb..85201461 100644 --- a/include/xwayland/selection.h +++ b/include/xwayland/selection.h @@ -7,6 +7,8 @@ #define XDND_VERSION 5 +struct wlr_primary_selection_source; + struct wlr_xwm_selection; struct wlr_xwm_selection_transfer { @@ -62,7 +64,7 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, xcb_xfixes_selection_notify_event_t *event); bool data_source_is_xwayland(struct wlr_data_source *wlr_source); bool primary_selection_source_is_xwayland( - struct wlr_gtk_primary_selection_source *wlr_source); + struct wlr_primary_selection_source *wlr_source); void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag); diff --git a/rootston/desktop.c b/rootston/desktop.c index dc5caad9..9b5291a3 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -957,16 +957,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); desktop->idle = wlr_idle_create(server->wl_display); desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display); - desktop->primary_selection_device_manager = wlr_gtk_primary_selection_device_manager_create(server->wl_display); -#if WLR_HAS_XWAYLAND - if (desktop->xwayland != NULL) { - wlr_xwayland_set_gtk_primary_selection_device_manager( - desktop->xwayland, desktop->primary_selection_device_manager); - } -#endif - desktop->input_inhibit = wlr_input_inhibit_manager_create(server->wl_display); desktop->input_inhibit_activate.notify = input_inhibit_activate; diff --git a/types/meson.build b/types/meson.build index f7653e55..03e5fcba 100644 --- a/types/meson.build +++ b/types/meson.build @@ -30,6 +30,7 @@ lib_wlr_types = static_library( 'wlr_export_dmabuf_v1.c', 'wlr_gamma_control_v1.c', 'wlr_gamma_control.c', + 'wlr_gtk_primary_selection.c', 'wlr_idle_inhibit_v1.c', 'wlr_idle.c', 'wlr_input_device.c', @@ -46,7 +47,7 @@ lib_wlr_types = static_library( 'wlr_pointer_constraints_v1.c', 'wlr_pointer.c', 'wlr_presentation_time.c', - 'wlr_gtk_primary_selection.c', + 'wlr_primary_selection.c', 'wlr_region.c', 'wlr_screencopy_v1.c', 'wlr_screenshooter.c', diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index 360f5c30..8b1d67fd 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "types/wlr_seat.h" @@ -162,6 +163,8 @@ void wlr_seat_destroy(struct wlr_seat *seat) { seat->selection_source = NULL; } + wlr_seat_set_primary_selection(seat, NULL); + struct wlr_seat_client *client, *tmp; wl_list_for_each_safe(client, tmp, &seat->clients, link) { struct wl_resource *resource, *next; diff --git a/types/wlr_gtk_primary_selection.c b/types/wlr_gtk_primary_selection.c index ebf4e5e3..5f349154 100644 --- a/types/wlr_gtk_primary_selection.c +++ b/types/wlr_gtk_primary_selection.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "gtk-primary-selection-protocol.h" @@ -24,12 +25,13 @@ static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { struct wlr_gtk_primary_selection_device *device = device_from_offer_resource(resource); - if (device == NULL || device->source == NULL) { + if (device == NULL || device->seat->primary_selection_source == NULL) { close(fd); return; } - wlr_gtk_primary_selection_source_send(device->source, mime_type, fd); + wlr_primary_selection_source_send(device->seat->primary_selection_source, + mime_type, fd); } static void offer_handle_destroy(struct wl_client *client, @@ -50,7 +52,7 @@ static struct wlr_gtk_primary_selection_device *device_from_resource( struct wl_resource *resource); static void create_offer(struct wl_resource *device_resource, - struct wlr_gtk_primary_selection_source *source) { + struct wlr_primary_selection_source *source) { struct wlr_gtk_primary_selection_device *device = device_from_resource(device_resource); assert(device != NULL); @@ -93,12 +95,12 @@ static void destroy_offer(struct wl_resource *resource) { struct client_data_source { - struct wlr_gtk_primary_selection_source source; + struct wlr_primary_selection_source source; struct wl_resource *resource; }; static void client_source_send( - struct wlr_gtk_primary_selection_source *wlr_source, + struct wlr_primary_selection_source *wlr_source, const char *mime_type, int fd) { struct client_data_source *source = (struct client_data_source *)wlr_source; gtk_primary_selection_source_send_send(source->resource, mime_type, fd); @@ -106,7 +108,7 @@ static void client_source_send( } static void client_source_destroy( - struct wlr_gtk_primary_selection_source *wlr_source) { + struct wlr_primary_selection_source *wlr_source) { struct client_data_source *source = (struct client_data_source *)wlr_source; gtk_primary_selection_source_send_cancelled(source->resource); // Make the source resource inert @@ -114,7 +116,7 @@ static void client_source_destroy( free(source); } -static const struct wlr_gtk_primary_selection_source_impl client_source_impl = { +static const struct wlr_primary_selection_source_impl client_source_impl = { .send = client_source_send, .destroy = client_source_destroy, }; @@ -136,16 +138,20 @@ static void source_handle_offer(struct wl_client *client, return; } - char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); - if (p) { - *p = strdup(mime_type); - } - if (p == NULL || *p == NULL) { - if (p) { - source->source.mime_types.size -= sizeof(*p); - } + char *dup_mime_type = strdup(mime_type); + if (dup_mime_type == NULL) { wl_resource_post_no_memory(resource); + return; } + + char **p = wl_array_add(&source->source.mime_types, sizeof(*p)); + if (p == NULL) { + free(dup_mime_type); + wl_resource_post_no_memory(resource); + return; + } + + *p = dup_mime_type; } static void source_handle_destroy(struct wl_client *client, @@ -164,7 +170,7 @@ static void source_resource_handle_destroy(struct wl_resource *resource) { if (source == NULL) { return; } - wlr_gtk_primary_selection_source_destroy(&source->source); + wlr_primary_selection_source_destroy(&source->source); } @@ -191,15 +197,14 @@ static void device_handle_set_selection(struct wl_client *client, client_source = client_data_source_from_resource(source_resource); } - struct wlr_gtk_primary_selection_source *source = NULL; + struct wlr_primary_selection_source *source = NULL; if (client_source != NULL) { source = &client_source->source; } - // TODO: improve serial checking - struct wlr_seat *seat = device->seat; - wlr_gtk_primary_selection_device_manager_set_selection(device->manager, - seat, source); + // TODO: serial checking + + wlr_seat_set_primary_selection(device->seat, source); } static void device_handle_destroy(struct wl_client *client, @@ -218,7 +223,7 @@ static void device_handle_resource_destroy(struct wl_resource *resource) { static void device_resource_send_selection(struct wl_resource *resource, - struct wlr_gtk_primary_selection_source *source) { + struct wlr_primary_selection_source *source) { assert(device_from_resource(resource) != NULL); if (source != NULL) { @@ -239,42 +244,12 @@ static void device_send_selection( struct wl_resource *resource; wl_resource_for_each(resource, &device->resources) { if (wl_resource_get_client(resource) == seat_client->client) { - device_resource_send_selection(resource, device->source); + device_resource_send_selection(resource, + device->seat->primary_selection_source); } } } -static void device_handle_source_destroy(struct wl_listener *listener, - void *data); - -static void device_set_selection( - struct wlr_gtk_primary_selection_device *device, - struct wlr_gtk_primary_selection_source *source) { - if (device->source != NULL) { - wl_list_remove(&device->source_destroy.link); - wlr_gtk_primary_selection_source_destroy(device->source); - device->source = NULL; - } - - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, &device->offers) { - destroy_offer(resource); - } - - device->source = source; - if (source != NULL) { - device->source_destroy.notify = device_handle_source_destroy; - wl_signal_add(&source->events.destroy, &device->source_destroy); - } - - device_send_selection(device); - - struct wlr_seat *seat = device->seat; - // TODO: remove these from wlr_seat - seat->primary_selection_source = source; - wlr_signal_emit_safe(&seat->events.primary_selection, seat); -} - static void device_destroy(struct wlr_gtk_primary_selection_device *device); static void device_handle_seat_destroy(struct wl_listener *listener, @@ -293,12 +268,16 @@ static void device_handle_seat_focus_change(struct wl_listener *listener, device_send_selection(device); } -static void device_handle_source_destroy(struct wl_listener *listener, +static void device_handle_seat_primary_selection(struct wl_listener *listener, void *data) { struct wlr_gtk_primary_selection_device *device = - wl_container_of(listener, device, source_destroy); - wl_list_remove(&device->source_destroy.link); - device->source = NULL; + wl_container_of(listener, device, seat_primary_selection); + + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &device->offers) { + destroy_offer(resource); + } + device_send_selection(device); } @@ -331,6 +310,11 @@ static struct wlr_gtk_primary_selection_device *get_or_create_device( wl_signal_add(&seat->keyboard_state.events.focus_change, &device->seat_focus_change); + device->seat_primary_selection.notify = + device_handle_seat_primary_selection; + wl_signal_add(&seat->events.primary_selection, + &device->seat_primary_selection); + return device; } @@ -341,10 +325,7 @@ static void device_destroy(struct wlr_gtk_primary_selection_device *device) { wl_list_remove(&device->link); wl_list_remove(&device->seat_destroy.link); wl_list_remove(&device->seat_focus_change.link); - if (device->source != NULL) { - wl_list_remove(&device->source_destroy.link); - wlr_gtk_primary_selection_source_destroy(device->source); - } + wl_list_remove(&device->seat_primary_selection.link); struct wl_resource *resource, *resource_tmp; wl_resource_for_each_safe(resource, resource_tmp, &device->offers) { destroy_offer(resource); @@ -379,7 +360,7 @@ static void device_manager_handle_create_source(struct wl_client *client, wl_client_post_no_memory(client); return; } - wlr_gtk_primary_selection_source_init(&source->source, &client_source_impl); + wlr_primary_selection_source_init(&source->source, &client_source_impl); uint32_t version = wl_resource_get_version(manager_resource); source->resource = wl_resource_create(client, @@ -420,7 +401,8 @@ void device_manager_handle_get_device(struct wl_client *client, wl_list_insert(&device->resources, wl_resource_get_link(resource)); if (device->seat->keyboard_state.focused_client == seat_client) { - device_resource_send_selection(resource, device->source); + device_resource_send_selection(resource, + device->seat->primary_selection_source); } } @@ -442,18 +424,6 @@ static void device_manager_handle_resource_destroy( } -void wlr_gtk_primary_selection_device_manager_set_selection( - struct wlr_gtk_primary_selection_device_manager *manager, - struct wlr_seat *seat, - struct wlr_gtk_primary_selection_source *source) { - struct wlr_gtk_primary_selection_device *device = - get_or_create_device(manager, seat); - if (device == NULL) { - return; - } - device_set_selection(device, source); -} - static void primary_selection_device_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wlr_gtk_primary_selection_device_manager *manager = data; @@ -516,40 +486,3 @@ void wlr_gtk_primary_selection_device_manager_destroy( wl_global_destroy(manager->global); free(manager); } - - -void wlr_gtk_primary_selection_source_init( - struct wlr_gtk_primary_selection_source *source, - const struct wlr_gtk_primary_selection_source_impl *impl) { - assert(impl->send); - wl_array_init(&source->mime_types); - wl_signal_init(&source->events.destroy); - source->impl = impl; -} - -void wlr_gtk_primary_selection_source_destroy( - struct wlr_gtk_primary_selection_source *source) { - if (source == NULL) { - return; - } - - wlr_signal_emit_safe(&source->events.destroy, source); - - char **p; - wl_array_for_each(p, &source->mime_types) { - free(*p); - } - wl_array_release(&source->mime_types); - - if (source->impl->destroy) { - source->impl->destroy(source); - } else { - free(source); - } -} - -void wlr_gtk_primary_selection_source_send( - struct wlr_gtk_primary_selection_source *source, const char *mime_type, - int32_t fd) { - source->impl->send(source, mime_type, fd); -} diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c new file mode 100644 index 00000000..921f44ee --- /dev/null +++ b/types/wlr_primary_selection.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "util/signal.h" + +void wlr_primary_selection_source_init( + struct wlr_primary_selection_source *source, + const struct wlr_primary_selection_source_impl *impl) { + assert(impl->send); + wl_array_init(&source->mime_types); + wl_signal_init(&source->events.destroy); + source->impl = impl; +} + +void wlr_primary_selection_source_destroy( + struct wlr_primary_selection_source *source) { + if (source == NULL) { + return; + } + + wlr_signal_emit_safe(&source->events.destroy, source); + + char **p; + wl_array_for_each(p, &source->mime_types) { + free(*p); + } + wl_array_release(&source->mime_types); + + if (source->impl->destroy) { + source->impl->destroy(source); + } else { + free(source); + } +} + +void wlr_primary_selection_source_send( + struct wlr_primary_selection_source *source, const char *mime_type, + int32_t fd) { + source->impl->send(source, mime_type, fd); +} + + +static void seat_handle_primary_selection_source_destroy( + struct wl_listener *listener, void *data) { + struct wlr_seat *seat = + wl_container_of(listener, seat, primary_selection_source_destroy); + wl_list_remove(&seat->primary_selection_source_destroy.link); + seat->primary_selection_source = NULL; + wlr_signal_emit_safe(&seat->events.primary_selection, seat); +} + +void wlr_seat_set_primary_selection(struct wlr_seat *seat, + struct wlr_primary_selection_source *source) { + if (seat->primary_selection_source != NULL) { + wl_list_remove(&seat->primary_selection_source_destroy.link); + wlr_primary_selection_source_destroy(seat->primary_selection_source); + seat->primary_selection_source = NULL; + } + + seat->primary_selection_source = source; + if (source != NULL) { + seat->primary_selection_source_destroy.notify = + seat_handle_primary_selection_source_destroy; + wl_signal_add(&source->events.destroy, + &seat->primary_selection_source_destroy); + } + + wlr_signal_emit_safe(&seat->events.primary_selection, seat); +} diff --git a/xwayland/selection/incoming.c b/xwayland/selection/incoming.c index 3342a761..3e97ca04 100644 --- a/xwayland/selection/incoming.c +++ b/xwayland/selection/incoming.c @@ -5,11 +5,11 @@ #include #include #include -#include +#include #include #include -#include "xwayland/xwm.h" #include "xwayland/selection.h" +#include "xwayland/xwm.h" /** * Write the X11 selection to a Wayland client. @@ -217,21 +217,21 @@ static const struct wlr_data_source_impl data_source_impl = { }; struct x11_primary_selection_source { - struct wlr_gtk_primary_selection_source base; + struct wlr_primary_selection_source base; struct wlr_xwm_selection *selection; struct wl_array mime_types_atoms; }; -static const struct wlr_gtk_primary_selection_source_impl +static const struct wlr_primary_selection_source_impl primary_selection_source_impl; bool primary_selection_source_is_xwayland( - struct wlr_gtk_primary_selection_source *wlr_source) { + struct wlr_primary_selection_source *wlr_source) { return wlr_source->impl == &primary_selection_source_impl; } static void primary_selection_source_send( - struct wlr_gtk_primary_selection_source *wlr_source, + struct wlr_primary_selection_source *wlr_source, const char *mime_type, int fd) { struct x11_primary_selection_source *source = (struct x11_primary_selection_source *)wlr_source; @@ -242,14 +242,14 @@ static void primary_selection_source_send( } static void primary_selection_source_destroy( - struct wlr_gtk_primary_selection_source *wlr_source) { + struct wlr_primary_selection_source *wlr_source) { struct x11_primary_selection_source *source = (struct x11_primary_selection_source *)wlr_source; wl_array_release(&source->mime_types_atoms); free(source); } -static const struct wlr_gtk_primary_selection_source_impl +static const struct wlr_primary_selection_source_impl primary_selection_source_impl = { .send = primary_selection_source_send, .destroy = primary_selection_source_destroy, @@ -361,7 +361,7 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { if (source == NULL) { return; } - wlr_gtk_primary_selection_source_init(&source->base, + wlr_primary_selection_source_init(&source->base, &primary_selection_source_impl); source->selection = selection; @@ -369,11 +369,10 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) { bool ok = source_get_targets(selection, &source->base.mime_types, &source->mime_types_atoms); - if (ok && xwm->xwayland->gtk_primary_selection) { - wlr_gtk_primary_selection_device_manager_set_selection( - xwm->xwayland->gtk_primary_selection, xwm->seat, &source->base); + if (ok) { + wlr_seat_set_primary_selection(xwm->seat, &source->base); } else { - wlr_gtk_primary_selection_source_destroy(&source->base); + wlr_primary_selection_source_destroy(&source->base); } } else if (selection == &xwm->dnd_selection) { // TODO @@ -427,10 +426,8 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm, if (selection == &xwm->clipboard_selection) { wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); - } else if (selection == &xwm->primary_selection && - xwm->xwayland->gtk_primary_selection) { - wlr_gtk_primary_selection_device_manager_set_selection( - xwm->xwayland->gtk_primary_selection, xwm->seat, NULL); + } else if (selection == &xwm->primary_selection) { + wlr_seat_set_primary_selection(xwm->seat, NULL); } else if (selection == &xwm->dnd_selection) { // TODO: DND } else { diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 1c994e18..fd5021d5 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -4,11 +4,11 @@ #include #include #include -#include +#include #include #include -#include "xwayland/xwm.h" #include "xwayland/selection.h" +#include "xwayland/xwm.h" static void xwm_selection_send_notify(struct wlr_xwm *xwm, xcb_selection_request_event_t *req, bool success) { @@ -195,10 +195,10 @@ static void xwm_selection_source_send(struct wlr_xwm_selection *selection, return; } } else if (selection == &selection->xwm->primary_selection) { - struct wlr_gtk_primary_selection_source *source = + struct wlr_primary_selection_source *source = selection->xwm->seat->primary_selection_source; if (source != NULL) { - wlr_gtk_primary_selection_source_send(source, mime_type, fd); + wlr_primary_selection_source_send(source, mime_type, fd); return; } } else if (selection == &selection->xwm->dnd_selection) { @@ -231,7 +231,7 @@ static struct wl_array *xwm_selection_source_get_mime_types( return &source->mime_types; } } else if (selection == &selection->xwm->primary_selection) { - struct wlr_gtk_primary_selection_source *source = + struct wlr_primary_selection_source *source = selection->xwm->seat->primary_selection_source; if (source != NULL) { return &source->mime_types; diff --git a/xwayland/selection/selection.c b/xwayland/selection/selection.c index db6246bf..4d7732cb 100644 --- a/xwayland/selection/selection.c +++ b/xwayland/selection/selection.c @@ -5,11 +5,11 @@ #include #include #include -#include +#include #include #include -#include "xwayland/xwm.h" #include "xwayland/selection.h" +#include "xwayland/xwm.h" void xwm_selection_transfer_remove_source( struct wlr_xwm_selection_transfer *transfer) { @@ -228,12 +228,10 @@ void xwm_selection_finish(struct wlr_xwm *xwm) { wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); } - if (xwm->xwayland->gtk_primary_selection && - xwm->seat->primary_selection_source && + if (xwm->seat->primary_selection_source && primary_selection_source_is_xwayland( xwm->seat->primary_selection_source)) { - wlr_gtk_primary_selection_device_manager_set_selection( - xwm->xwayland->gtk_primary_selection, xwm->seat, NULL); + wlr_seat_set_primary_selection(xwm->seat, NULL); } wlr_xwayland_set_seat(xwm->xwayland, NULL); } @@ -275,11 +273,10 @@ static void seat_handle_primary_selection(struct wl_listener *listener, struct wlr_seat *seat = data; struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_primary_selection); - struct wlr_gtk_primary_selection_source *source = seat->primary_selection_source; + struct wlr_primary_selection_source *source = + seat->primary_selection_source; - if (source != NULL && - primary_selection_source_is_xwayland( - source)) { + if (source != NULL && primary_selection_source_is_xwayland(source)) { return; } diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index bbdee1a7..e6d3502c 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -505,9 +505,3 @@ void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, xwayland->seat_destroy.notify = xwayland_handle_seat_destroy; wl_signal_add(&seat->events.destroy, &xwayland->seat_destroy); } - -void wlr_xwayland_set_gtk_primary_selection_device_manager( - struct wlr_xwayland *xwayland, - struct wlr_gtk_primary_selection_device_manager *manager) { - xwayland->gtk_primary_selection = manager; -}