aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremersion <contact@emersion.fr>2017-12-22 22:22:29 +0100
committeremersion <contact@emersion.fr>2017-12-22 22:22:29 +0100
commita95d09d56181fe9bd639239b723942c5a333a245 (patch)
tree49ec4e6bd7bddb5012af2ca8750bdcd31a22d30b
parent0a171d3acec825b5a9115907b339dc29aec678fa (diff)
Add missing gtk-primary-selection interfaces
-rw-r--r--include/rootston/desktop.h2
-rw-r--r--include/wlr/types/wlr_primary_selection.h23
-rw-r--r--include/wlr/types/wlr_seat.h6
-rw-r--r--rootston/desktop.c3
-rw-r--r--types/wlr_primary_selection.c246
-rw-r--r--types/wlr_seat.c5
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,
+ &gtk_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);