From 0a171d3acec825b5a9115907b339dc29aec678fa Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 22 Dec 2017 19:20:12 +0100 Subject: Add wlr_primary_selection_device_manager and wlr_primary_selection_source --- include/wlr/types/wlr_primary_selection.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 include/wlr/types/wlr_primary_selection.h (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h new file mode 100644 index 00000000..edbaf81e --- /dev/null +++ b/include/wlr/types/wlr_primary_selection.h @@ -0,0 +1,31 @@ +#ifndef WLR_TYPES_WLR_PRIMARY_SELECTION_H +#define WLR_TYPES_WLR_PRIMARY_SELECTION_H + +#include + +struct wlr_primary_selection_device_manager { + struct wl_global *global; + + struct wl_listener display_destroy; + + void *data; +}; + +struct wlr_primary_selection_source { + struct wl_resource *resource; + + struct wl_array mime_types; + + struct { + struct wl_signal destroy; + } events; + + void *data; +}; + +struct wlr_primary_selection_device_manager * + wlr_primary_selection_device_manager_create(struct wl_display *display); +void wlr_primary_selection_device_manager_destroy( + struct wlr_primary_selection_device_manager *manager); + +#endif -- cgit v1.2.3 From a95d09d56181fe9bd639239b723942c5a333a245 Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 22 Dec 2017 22:22:29 +0100 Subject: Add missing gtk-primary-selection interfaces --- include/rootston/desktop.h | 2 + include/wlr/types/wlr_primary_selection.h | 23 +++ include/wlr/types/wlr_seat.h | 6 + rootston/desktop.c | 3 + types/wlr_primary_selection.c | 246 +++++++++++++++++++++++++++++- types/wlr_seat.c | 5 + 6 files changed, 278 insertions(+), 7 deletions(-) (limited to 'include/wlr') diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index e5c5f806..289875c5 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "rootston/view.h" @@ -41,6 +42,7 @@ struct roots_desktop { struct wlr_gamma_control_manager *gamma_control_manager; struct wlr_screenshooter *screenshooter; struct wlr_server_decoration_manager *server_decoration_manager; + struct wlr_primary_selection_device_manager *primary_selection_device_manager; struct wl_listener output_add; struct wl_listener output_remove; diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h index edbaf81e..e69feb89 100644 --- a/include/wlr/types/wlr_primary_selection.h +++ b/include/wlr/types/wlr_primary_selection.h @@ -1,6 +1,7 @@ #ifndef WLR_TYPES_WLR_PRIMARY_SELECTION_H #define WLR_TYPES_WLR_PRIMARY_SELECTION_H +#include #include struct wlr_primary_selection_device_manager { @@ -11,10 +12,21 @@ struct wlr_primary_selection_device_manager { void *data; }; +struct wlr_primary_selection_offer; + struct wlr_primary_selection_source { struct wl_resource *resource; + struct wlr_primary_selection_offer *offer; + struct wlr_seat_client *seat_client; struct wl_array mime_types; + bool accepted; + + void (*accept)(struct wlr_primary_selection_source *source, uint32_t serial, + const char *mime_type); + void (*send)(struct wlr_primary_selection_source *source, + const char *mime_type, int32_t fd); + void (*cancel)(struct wlr_primary_selection_source *source); struct { struct wl_signal destroy; @@ -23,9 +35,20 @@ struct wlr_primary_selection_source { void *data; }; +struct wlr_primary_selection_offer { + struct wl_resource *resource; + struct wlr_primary_selection_source *source; + + struct wl_listener source_destroy; +}; + struct wlr_primary_selection_device_manager * wlr_primary_selection_device_manager_create(struct wl_display *display); void wlr_primary_selection_device_manager_destroy( struct wlr_primary_selection_device_manager *manager); +void wlr_seat_client_send_primary_selection(struct wlr_seat_client *seat_client); +void wlr_seat_set_primary_selection(struct wlr_seat *seat, + struct wlr_primary_selection_source *source, uint32_t serial); + #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index dea9a9d0..28e9a615 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -21,6 +21,7 @@ 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; @@ -181,12 +182,16 @@ struct wlr_seat { struct wlr_data_source *selection_source; uint32_t selection_serial; + struct wlr_primary_selection_source *primary_selection_source; + uint32_t primary_selection_serial; + struct wlr_seat_pointer_state pointer_state; struct wlr_seat_keyboard_state keyboard_state; struct wlr_seat_touch_state touch_state; struct wl_listener display_destroy; struct wl_listener selection_data_source_destroy; + struct wl_listener primary_selection_source_destroy; struct { struct wl_signal pointer_grab_begin; @@ -201,6 +206,7 @@ struct wlr_seat { struct wl_signal request_set_cursor; struct wl_signal selection; + struct wl_signal primary_selection; } events; void *data; diff --git a/rootston/desktop.c b/rootston/desktop.c index c9fc0dc6..1431dc5d 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -470,6 +471,8 @@ 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_primary_selection_device_manager_create(server->wl_display); return desktop; } diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index 7ed4a402..a83029c4 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -1,10 +1,118 @@ #define _XOPEN_SOURCE 700 #include +#include #include #include #include +#include #include +static void client_source_accept(struct wlr_primary_selection_source *source, + uint32_t serial, const char *mime_type) {} + +static void client_source_send(struct wlr_primary_selection_source *source, + const char *mime_type, int32_t fd) { + gtk_primary_selection_source_send_send(source->resource, mime_type, fd); + close(fd); +} + +static void client_source_cancel( + struct wlr_primary_selection_source *source) { + gtk_primary_selection_source_send_cancelled(source->resource); +} + + +static void offer_handle_receive(struct wl_client *client, + struct wl_resource *resource, const char *mime_type, int32_t fd) { + // TODO +} + +static void offer_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct gtk_primary_selection_offer_interface offer_impl = { + .receive = offer_handle_receive, + .destroy = offer_handle_destroy, +}; + +static void offer_resource_handle_destroy(struct wl_resource *resource) { + struct wlr_primary_selection_offer *offer = + wl_resource_get_user_data(resource); + + if (!offer->source) { + goto out; + } + + wl_list_remove(&offer->source_destroy.link); + + if (offer->source->offer != offer) { + goto out; + } + + if (offer->source->resource) { + wl_data_source_send_cancelled(offer->source->resource); + } + + offer->source->offer = NULL; +out: + free(offer); +} + +static void offer_handle_source_destroy(struct wl_listener *listener, + void *data) { + struct wlr_primary_selection_offer *offer = + wl_container_of(listener, offer, source_destroy); + + offer->source = NULL; +} + + +static struct wlr_primary_selection_offer *source_send_offer( + struct wlr_primary_selection_source *source, + struct wlr_seat_client *target) { + if (wl_list_empty(&target->data_devices)) { + return NULL; + } + + struct wlr_primary_selection_offer *offer = + calloc(1, sizeof(struct wlr_primary_selection_offer)); + if (offer == NULL) { + return NULL; + } + + uint32_t version = wl_resource_get_version( + wl_resource_from_link(target->data_devices.next)); + offer->resource = wl_resource_create(target->client, + &wl_data_offer_interface, version, 0); + if (offer->resource == NULL) { + free(offer); + return NULL; + } + wl_resource_set_implementation(offer->resource, &offer_impl, offer, + offer_resource_handle_destroy); + + offer->source_destroy.notify = offer_handle_source_destroy; + wl_signal_add(&source->events.destroy, &offer->source_destroy); + + struct wl_resource *target_resource; + wl_resource_for_each(target_resource, &target->data_devices) { + wl_data_device_send_data_offer(target_resource, offer->resource); + } + + char **p; + wl_array_for_each(p, &source->mime_types) { + wl_data_offer_send_offer(offer->resource, *p); + } + + offer->source = source; + source->offer = offer; + source->accepted = false; + + return offer; +} + static void source_handle_offer(struct wl_client *client, struct wl_resource *resource, const char *mime_type) { struct wlr_primary_selection_source *source = @@ -36,11 +144,114 @@ static void source_resource_handle_destroy( struct wl_resource *resource) { free(source); } + +void wlr_seat_client_send_primary_selection( + struct wlr_seat_client *seat_client) { + if (wl_list_empty(&seat_client->primary_selection_devices)) { + return; + } + + if (seat_client->seat->primary_selection_source) { + struct wlr_primary_selection_offer *offer = source_send_offer( + seat_client->seat->primary_selection_source, seat_client); + if (offer == NULL) { + return; + } + + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->primary_selection_devices) { + wl_data_device_send_selection(resource, offer->resource); + } + } else { + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->primary_selection_devices) { + wl_data_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) { + wl_data_device_send_selection(resource, NULL); + } + } + + seat->primary_selection_source = NULL; + + wl_signal_emit(&seat->events.primary_selection, seat); +} + +void wlr_seat_set_primary_selection(struct wlr_seat *seat, + struct wlr_primary_selection_source *source, uint32_t serial) { + if (seat->primary_selection_source && + seat->primary_selection_serial - serial < UINT32_MAX / 2) { + return; + } + + if (seat->primary_selection_source) { + seat->primary_selection_source->cancel(seat->primary_selection_source); + seat->primary_selection_source = NULL; + wl_list_remove(&seat->primary_selection_source_destroy.link); + } + + 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_primary_selection(focused_client); + } + + wl_signal_emit(&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 void device_handle_set_selection(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *source_resource, + uint32_t serial) { + struct wlr_primary_selection_source *source = NULL; + if (source_resource != NULL) { + source = wl_resource_get_user_data(source_resource); + } + + struct wlr_seat_client *seat_client = + wl_resource_get_user_data(resource); + + // TODO: store serial and check against incoming serial here + wlr_seat_set_primary_selection(seat_client->seat, source, serial); +} + +static void device_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct gtk_primary_selection_device_interface device_impl = { + .set_selection = device_handle_set_selection, + .destroy = device_handle_destroy, +}; + +static void device_resource_handle_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + + static void device_manager_handle_create_source(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id) { - //struct wlr_primary_selection_device_manager *manager = - // wl_resource_get_user_data(manager_resource); - struct wlr_primary_selection_source *source = calloc(1, sizeof(struct wlr_primary_selection_source)); if (source == NULL) { @@ -59,11 +270,31 @@ static void device_manager_handle_create_source(struct wl_client *client, wl_resource_set_implementation(source->resource, &source_impl, source, source_resource_handle_destroy); - wl_signal_init(&source->events.destroy); + source->accept = client_source_accept; + source->send = client_source_send; + source->cancel = client_source_cancel; + wl_array_init(&source->mime_types); + wl_signal_init(&source->events.destroy); +} - wlr_log(L_DEBUG, "new gtk_primary_selection_source %p (res %p)", source, - source->resource); +void device_manager_handle_get_device(struct wl_client *client, + struct wl_resource *manager_resource, uint32_t id, + struct wl_resource *seat_resource) { + struct wlr_seat_client *seat_client = + wl_resource_get_user_data(seat_resource); + + uint32_t version = wl_resource_get_version(manager_resource); + struct wl_resource *resource = wl_resource_create(client, + >k_primary_selection_device_interface, version, id); + if (resource == NULL) { + 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)); } static void device_manager_handle_destroy(struct wl_client *client, @@ -74,10 +305,11 @@ static void device_manager_handle_destroy(struct wl_client *client, static const struct gtk_primary_selection_device_manager_interface device_manager_impl = { .create_source = device_manager_handle_create_source, - //.get_device = device_manager_handle_get_device, + .get_device = device_manager_handle_get_device, .destroy = device_manager_handle_destroy, }; + static void primary_selection_device_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { struct wlr_primary_selection_device_manager *manager = data; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 25b1fcd4..feb78999 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -198,6 +198,9 @@ static void wlr_seat_client_resource_destroy(struct wl_resource *seat_resource) 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); @@ -234,6 +237,7 @@ static void wl_seat_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_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl, seat_client, wlr_seat_client_resource_destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); @@ -437,6 +441,7 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_signal_init(&wlr_seat->events.request_set_cursor); wl_signal_init(&wlr_seat->events.selection); + wl_signal_init(&wlr_seat->events.primary_selection); wl_signal_init(&wlr_seat->events.pointer_grab_begin); wl_signal_init(&wlr_seat->events.pointer_grab_end); -- cgit v1.2.3 From 4476f798508341b9ac931f9e623d7b77197a163a Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 22 Dec 2017 23:45:07 +0100 Subject: Fix primary clipboard issues --- include/wlr/types/wlr_primary_selection.h | 5 ++--- types/wlr_primary_selection.c | 35 +++++++++++++++++-------------- 2 files changed, 21 insertions(+), 19 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_primary_selection.h b/include/wlr/types/wlr_primary_selection.h index e69feb89..a639b913 100644 --- a/include/wlr/types/wlr_primary_selection.h +++ b/include/wlr/types/wlr_primary_selection.h @@ -20,10 +20,7 @@ struct wlr_primary_selection_source { struct wlr_seat_client *seat_client; struct wl_array mime_types; - bool accepted; - void (*accept)(struct wlr_primary_selection_source *source, uint32_t serial, - const char *mime_type); void (*send)(struct wlr_primary_selection_source *source, const char *mime_type, int32_t fd); void (*cancel)(struct wlr_primary_selection_source *source); @@ -40,6 +37,8 @@ struct wlr_primary_selection_offer { struct wlr_primary_selection_source *source; struct wl_listener source_destroy; + + void *data; }; struct wlr_primary_selection_device_manager * diff --git a/types/wlr_primary_selection.c b/types/wlr_primary_selection.c index a83029c4..dbbf1eaa 100644 --- a/types/wlr_primary_selection.c +++ b/types/wlr_primary_selection.c @@ -7,9 +7,6 @@ #include #include -static void client_source_accept(struct wlr_primary_selection_source *source, - uint32_t serial, const char *mime_type) {} - static void client_source_send(struct wlr_primary_selection_source *source, const char *mime_type, int32_t fd) { gtk_primary_selection_source_send_send(source->resource, mime_type, fd); @@ -24,7 +21,14 @@ static void client_source_cancel( static void offer_handle_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - // TODO + struct wlr_primary_selection_offer *offer = + wl_resource_get_user_data(resource); + + if (offer->source && offer == offer->source->offer) { + offer->source->send(offer->source, mime_type, fd); + } else { + close(fd); + } } static void offer_handle_destroy(struct wl_client *client, @@ -52,7 +56,7 @@ static void offer_resource_handle_destroy(struct wl_resource *resource) { } if (offer->source->resource) { - wl_data_source_send_cancelled(offer->source->resource); + gtk_primary_selection_source_send_cancelled(offer->source->resource); } offer->source->offer = NULL; @@ -72,7 +76,7 @@ static void offer_handle_source_destroy(struct wl_listener *listener, static struct wlr_primary_selection_offer *source_send_offer( struct wlr_primary_selection_source *source, struct wlr_seat_client *target) { - if (wl_list_empty(&target->data_devices)) { + if (wl_list_empty(&target->primary_selection_devices)) { return NULL; } @@ -83,9 +87,9 @@ static struct wlr_primary_selection_offer *source_send_offer( } uint32_t version = wl_resource_get_version( - wl_resource_from_link(target->data_devices.next)); + wl_resource_from_link(target->primary_selection_devices.next)); offer->resource = wl_resource_create(target->client, - &wl_data_offer_interface, version, 0); + >k_primary_selection_offer_interface, version, 0); if (offer->resource == NULL) { free(offer); return NULL; @@ -97,18 +101,18 @@ static struct wlr_primary_selection_offer *source_send_offer( wl_signal_add(&source->events.destroy, &offer->source_destroy); struct wl_resource *target_resource; - wl_resource_for_each(target_resource, &target->data_devices) { - wl_data_device_send_data_offer(target_resource, offer->resource); + wl_resource_for_each(target_resource, &target->primary_selection_devices) { + gtk_primary_selection_device_send_data_offer(target_resource, + offer->resource); } char **p; wl_array_for_each(p, &source->mime_types) { - wl_data_offer_send_offer(offer->resource, *p); + gtk_primary_selection_offer_send_offer(offer->resource, *p); } offer->source = source; source->offer = offer; - source->accepted = false; return offer; } @@ -160,12 +164,12 @@ void wlr_seat_client_send_primary_selection( struct wl_resource *resource; wl_resource_for_each(resource, &seat_client->primary_selection_devices) { - wl_data_device_send_selection(resource, offer->resource); + gtk_primary_selection_device_send_selection(resource, offer->resource); } } else { struct wl_resource *resource; wl_resource_for_each(resource, &seat_client->primary_selection_devices) { - wl_data_device_send_selection(resource, NULL); + gtk_primary_selection_device_send_selection(resource, NULL); } } } @@ -179,7 +183,7 @@ static void seat_client_primary_selection_source_destroy( if (seat_client && seat->keyboard_state.focused_surface) { struct wl_resource *resource; wl_resource_for_each(resource, &seat_client->primary_selection_devices) { - wl_data_device_send_selection(resource, NULL); + gtk_primary_selection_device_send_selection(resource, NULL); } } @@ -270,7 +274,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->accept = client_source_accept; source->send = client_source_send; source->cancel = client_source_cancel; -- cgit v1.2.3