Merge pull request #1380 from emersion/gtk-primary-selection-multiple-devices

gtk-primary-selection: support multiple devices
This commit is contained in:
emersion 2018-11-21 22:29:36 +01:00 committed by GitHub
commit 42e8e3ed0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 62 deletions

View file

@ -14,6 +14,7 @@
struct wlr_primary_selection_device_manager { struct wlr_primary_selection_device_manager {
struct wl_global *global; struct wl_global *global;
struct wl_list resources;
struct wl_listener display_destroy; struct wl_listener display_destroy;
@ -24,8 +25,6 @@ struct wlr_primary_selection_device_manager {
void *data; void *data;
}; };
struct wlr_primary_selection_offer;
struct wlr_primary_selection_source { struct wlr_primary_selection_source {
// source metadata // source metadata
struct wl_array mime_types; struct wl_array mime_types;
@ -36,7 +35,6 @@ struct wlr_primary_selection_source {
void (*cancel)(struct wlr_primary_selection_source *source); void (*cancel)(struct wlr_primary_selection_source *source);
// source status // source status
struct wlr_primary_selection_offer *offer;
struct wlr_seat_client *seat_client; struct wlr_seat_client *seat_client;
struct { struct {

View file

@ -9,6 +9,8 @@
#include "gtk-primary-selection-protocol.h" #include "gtk-primary-selection-protocol.h"
#include "util/signal.h" #include "util/signal.h"
#define DEVICE_MANAGER_VERSION 1
static const struct gtk_primary_selection_offer_interface offer_impl; static const struct gtk_primary_selection_offer_interface offer_impl;
static struct wlr_primary_selection_offer *offer_from_resource( static struct wlr_primary_selection_offer *offer_from_resource(
@ -21,12 +23,12 @@ static struct wlr_primary_selection_offer *offer_from_resource(
static void offer_handle_receive(struct wl_client *client, static void offer_handle_receive(struct wl_client *client,
struct wl_resource *resource, const char *mime_type, int32_t fd) { struct wl_resource *resource, const char *mime_type, int32_t fd) {
struct wlr_primary_selection_offer *offer = offer_from_resource(resource); struct wlr_primary_selection_offer *offer = offer_from_resource(resource);
if (offer == NULL) {
if (offer->source && offer == offer->source->offer) {
offer->source->send(offer->source, mime_type, fd);
} else {
close(fd); close(fd);
return;
} }
offer->source->send(offer->source, mime_type, fd);
} }
static void offer_handle_destroy(struct wl_client *client, static void offer_handle_destroy(struct wl_client *client,
@ -39,31 +41,26 @@ static const struct gtk_primary_selection_offer_interface offer_impl = {
.destroy = offer_handle_destroy, .destroy = offer_handle_destroy,
}; };
static void offer_resource_handle_destroy(struct wl_resource *resource) { static void offer_destroy(struct wlr_primary_selection_offer *offer) {
struct wlr_primary_selection_offer *offer = offer_from_resource(resource); if (offer == NULL) {
return;
if (!offer->source) {
goto out;
} }
// Make resource inert
wl_resource_set_user_data(offer->resource, NULL);
wl_list_remove(&offer->source_destroy.link); wl_list_remove(&offer->source_destroy.link);
free(offer);
if (offer->source->offer != offer) {
goto out;
} }
offer->source->offer = NULL; static void offer_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_primary_selection_offer *offer = offer_from_resource(resource);
out: offer_destroy(offer);
free(offer);
} }
static void offer_handle_source_destroy(struct wl_listener *listener, static void offer_handle_source_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_primary_selection_offer *offer = struct wlr_primary_selection_offer *offer =
wl_container_of(listener, offer, source_destroy); wl_container_of(listener, offer, source_destroy);
offer_destroy(offer);
offer->source = NULL;
} }
@ -85,38 +82,32 @@ static void client_source_cancel(
gtk_primary_selection_source_send_cancelled(source->resource); gtk_primary_selection_source_send_cancelled(source->resource);
} }
static struct wlr_primary_selection_offer *source_send_offer( static void source_send_offer(struct wlr_primary_selection_source *source,
struct wlr_primary_selection_source *source, struct wl_resource *device_resource) {
struct wlr_seat_client *target) {
if (wl_list_empty(&target->primary_selection_devices)) {
return NULL;
}
struct wlr_primary_selection_offer *offer = struct wlr_primary_selection_offer *offer =
calloc(1, sizeof(struct wlr_primary_selection_offer)); calloc(1, sizeof(struct wlr_primary_selection_offer));
if (offer == NULL) { if (offer == NULL) {
return NULL; wl_resource_post_no_memory(device_resource);
return;
} }
uint32_t version = wl_resource_get_version( struct wl_client *client = wl_resource_get_client(device_resource);
wl_resource_from_link(target->primary_selection_devices.next)); uint32_t version = wl_resource_get_version(device_resource);
offer->resource = wl_resource_create(target->client, offer->resource = wl_resource_create(client,
&gtk_primary_selection_offer_interface, version, 0); &gtk_primary_selection_offer_interface, version, 0);
if (offer->resource == NULL) { if (offer->resource == NULL) {
free(offer); free(offer);
return NULL; wl_resource_post_no_memory(device_resource);
return;
} }
wl_resource_set_implementation(offer->resource, &offer_impl, offer, wl_resource_set_implementation(offer->resource, &offer_impl, offer,
offer_resource_handle_destroy); offer_handle_resource_destroy);
offer->source_destroy.notify = offer_handle_source_destroy; offer->source_destroy.notify = offer_handle_source_destroy;
wl_signal_add(&source->events.destroy, &offer->source_destroy); wl_signal_add(&source->events.destroy, &offer->source_destroy);
struct wl_resource *target_resource; gtk_primary_selection_device_send_data_offer(device_resource,
wl_resource_for_each(target_resource, &target->primary_selection_devices) {
gtk_primary_selection_device_send_data_offer(target_resource,
offer->resource); offer->resource);
}
char **p; char **p;
wl_array_for_each(p, &source->mime_types) { wl_array_for_each(p, &source->mime_types) {
@ -124,9 +115,9 @@ static struct wlr_primary_selection_offer *source_send_offer(
} }
offer->source = source; offer->source = source;
source->offer = offer;
return offer; gtk_primary_selection_device_send_selection(device_resource,
offer->resource);
} }
static const struct gtk_primary_selection_source_interface source_impl; static const struct gtk_primary_selection_source_interface source_impl;
@ -179,20 +170,13 @@ void wlr_seat_client_send_primary_selection(
return; return;
} }
if (seat_client->seat->primary_selection_source) { struct wlr_primary_selection_source *source =
struct wlr_primary_selection_offer *offer = source_send_offer( seat_client->seat->primary_selection_source;
seat_client->seat->primary_selection_source, seat_client);
if (offer == NULL) {
return;
}
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &seat_client->primary_selection_devices) { wl_resource_for_each(resource, &seat_client->primary_selection_devices) {
gtk_primary_selection_device_send_selection(resource, offer->resource); if (source) {
} source_send_offer(source, resource);
} else { } else {
struct wl_resource *resource;
wl_resource_for_each(resource, &seat_client->primary_selection_devices) {
gtk_primary_selection_device_send_selection(resource, NULL); gtk_primary_selection_device_send_selection(resource, NULL);
} }
} }
@ -228,6 +212,7 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat,
return; return;
} }
// TODO: make all offers inert
if (seat->primary_selection_source) { if (seat->primary_selection_source) {
wl_list_remove(&seat->primary_selection_source_destroy.link); wl_list_remove(&seat->primary_selection_source_destroy.link);
seat->primary_selection_source->cancel(seat->primary_selection_source); seat->primary_selection_source->cancel(seat->primary_selection_source);
@ -371,6 +356,11 @@ device_manager_impl = {
.destroy = device_manager_handle_destroy, .destroy = device_manager_handle_destroy,
}; };
static void device_manager_handle_resource_destroy(
struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
}
static void primary_selection_device_manager_bind(struct wl_client *client, static void primary_selection_device_manager_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id) { void *data, uint32_t version, uint32_t id) {
@ -383,7 +373,9 @@ static void primary_selection_device_manager_bind(struct wl_client *client,
return; return;
} }
wl_resource_set_implementation(resource, &device_manager_impl, manager, wl_resource_set_implementation(resource, &device_manager_impl, manager,
NULL); device_manager_handle_resource_destroy);
wl_list_insert(&manager->resources, wl_resource_get_link(resource));
} }
static void handle_display_destroy(struct wl_listener *listener, void *data) { static void handle_display_destroy(struct wl_listener *listener, void *data) {
@ -401,13 +393,14 @@ struct wlr_primary_selection_device_manager *
return NULL; return NULL;
} }
manager->global = wl_global_create(display, manager->global = wl_global_create(display,
&gtk_primary_selection_device_manager_interface, 1, manager, &gtk_primary_selection_device_manager_interface, DEVICE_MANAGER_VERSION,
primary_selection_device_manager_bind); manager, primary_selection_device_manager_bind);
if (manager->global == NULL) { if (manager->global == NULL) {
free(manager); free(manager);
return NULL; return NULL;
} }
wl_list_init(&manager->resources);
wl_signal_init(&manager->events.destroy); wl_signal_init(&manager->events.destroy);
manager->display_destroy.notify = handle_display_destroy; manager->display_destroy.notify = handle_display_destroy;
@ -423,7 +416,10 @@ void wlr_primary_selection_device_manager_destroy(
} }
wlr_signal_emit_safe(&manager->events.destroy, manager); wlr_signal_emit_safe(&manager->events.destroy, manager);
wl_list_remove(&manager->display_destroy.link); wl_list_remove(&manager->display_destroy.link);
// TODO: free resources struct wl_resource *resource, *resource_tmp;
wl_resource_for_each_safe(resource, resource_tmp, &manager->resources) {
wl_resource_destroy(resource);
}
wl_global_destroy(manager->global); wl_global_destroy(manager->global);
free(manager); free(manager);
} }