diff options
author | emersion <contact@emersion.fr> | 2017-12-22 22:22:29 +0100 |
---|---|---|
committer | emersion <contact@emersion.fr> | 2017-12-22 22:22:29 +0100 |
commit | a95d09d56181fe9bd639239b723942c5a333a245 (patch) | |
tree | 49ec4e6bd7bddb5012af2ca8750bdcd31a22d30b | |
parent | 0a171d3acec825b5a9115907b339dc29aec678fa (diff) |
Add missing gtk-primary-selection interfaces
-rw-r--r-- | include/rootston/desktop.h | 2 | ||||
-rw-r--r-- | include/wlr/types/wlr_primary_selection.h | 23 | ||||
-rw-r--r-- | include/wlr/types/wlr_seat.h | 6 | ||||
-rw-r--r-- | rootston/desktop.c | 3 | ||||
-rw-r--r-- | types/wlr_primary_selection.c | 246 | ||||
-rw-r--r-- | types/wlr_seat.c | 5 |
6 files changed, 278 insertions, 7 deletions
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 <wlr/types/wlr_xdg_shell_v6.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_screenshooter.h> #include <wlr/types/wlr_list.h> #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 <wlr/types/wlr_seat.h> #include <wayland-server.h> 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 <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_gamma_control.h> +#include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_wl_shell.h> @@ -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 <stdlib.h> +#include <unistd.h> #include <string.h> #include <gtk-primary-selection-protocol.h> #include <wlr/types/wlr_primary_selection.h> +#include <wlr/types/wlr_seat.h> #include <wlr/util/log.h> +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); |