Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

gtk-primary-selection: support multiple devices #1380

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions include/wlr/types/wlr_primary_selection.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

struct wlr_primary_selection_device_manager {
struct wl_global *global;
struct wl_list resources;

struct wl_listener display_destroy;

Expand All @@ -24,8 +25,6 @@ struct wlr_primary_selection_device_manager {
void *data;
};

struct wlr_primary_selection_offer;

struct wlr_primary_selection_source {
// source metadata
struct wl_array mime_types;
Expand All @@ -36,7 +35,6 @@ struct wlr_primary_selection_source {
void (*cancel)(struct wlr_primary_selection_source *source);

// source status
struct wlr_primary_selection_offer *offer;
struct wlr_seat_client *seat_client;

struct {
Expand Down
114 changes: 55 additions & 59 deletions types/wlr_primary_selection.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "gtk-primary-selection-protocol.h"
#include "util/signal.h"

#define DEVICE_MANAGER_VERSION 1

static const struct gtk_primary_selection_offer_interface offer_impl;

static struct wlr_primary_selection_offer *offer_from_resource(
Expand All @@ -21,12 +23,12 @@ static struct wlr_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_primary_selection_offer *offer = offer_from_resource(resource);

if (offer->source && offer == offer->source->offer) {
offer->source->send(offer->source, mime_type, fd);
} else {
if (offer == NULL) {
close(fd);
return;
}

offer->source->send(offer->source, mime_type, fd);
}

static void offer_handle_destroy(struct wl_client *client,
Expand All @@ -39,31 +41,26 @@ static const struct gtk_primary_selection_offer_interface offer_impl = {
.destroy = offer_handle_destroy,
};

static void offer_resource_handle_destroy(struct wl_resource *resource) {
struct wlr_primary_selection_offer *offer = offer_from_resource(resource);

if (!offer->source) {
goto out;
static void offer_destroy(struct wlr_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);

if (offer->source->offer != offer) {
goto out;
}

offer->source->offer = NULL;

out:
free(offer);
}

static void offer_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_primary_selection_offer *offer = offer_from_resource(resource);
offer_destroy(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;
offer_destroy(offer);
}


Expand All @@ -85,48 +82,42 @@ static void client_source_cancel(
gtk_primary_selection_source_send_cancelled(source->resource);
}

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->primary_selection_devices)) {
return NULL;
}

static void source_send_offer(struct wlr_primary_selection_source *source,
struct wl_resource *device_resource) {
struct wlr_primary_selection_offer *offer =
calloc(1, sizeof(struct wlr_primary_selection_offer));
if (offer == NULL) {
return NULL;
wl_resource_post_no_memory(device_resource);
return;
}

uint32_t version = wl_resource_get_version(
wl_resource_from_link(target->primary_selection_devices.next));
offer->resource = wl_resource_create(target->client,
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,
&gtk_primary_selection_offer_interface, version, 0);
if (offer->resource == NULL) {
free(offer);
return NULL;
wl_resource_post_no_memory(device_resource);
return;
}
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;
wl_signal_add(&source->events.destroy, &offer->source_destroy);

struct wl_resource *target_resource;
wl_resource_for_each(target_resource, &target->primary_selection_devices) {
gtk_primary_selection_device_send_data_offer(target_resource,
offer->resource);
}
gtk_primary_selection_device_send_data_offer(device_resource,
offer->resource);

char **p;
wl_array_for_each(p, &source->mime_types) {
gtk_primary_selection_offer_send_offer(offer->resource, *p);
}

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;
Expand Down Expand Up @@ -179,20 +170,13 @@ void wlr_seat_client_send_primary_selection(
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) {
gtk_primary_selection_device_send_selection(resource, offer->resource);
}
} else {
struct wl_resource *resource;
wl_resource_for_each(resource, &seat_client->primary_selection_devices) {
struct wlr_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);
}
}
Expand Down Expand Up @@ -228,6 +212,7 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat,
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);
Expand Down Expand Up @@ -365,12 +350,17 @@ static void device_manager_handle_destroy(struct wl_client *client,
}

static const struct gtk_primary_selection_device_manager_interface
device_manager_impl = {
device_manager_impl = {
.create_source = device_manager_handle_create_source,
.get_device = device_manager_handle_get_device,
.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,
void *data, uint32_t version, uint32_t id) {
Expand All @@ -383,7 +373,9 @@ static void primary_selection_device_manager_bind(struct wl_client *client,
return;
}
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) {
Expand All @@ -401,13 +393,14 @@ struct wlr_primary_selection_device_manager *
return NULL;
}
manager->global = wl_global_create(display,
&gtk_primary_selection_device_manager_interface, 1, manager,
primary_selection_device_manager_bind);
&gtk_primary_selection_device_manager_interface, DEVICE_MANAGER_VERSION,
manager, primary_selection_device_manager_bind);
if (manager->global == NULL) {
free(manager);
return NULL;
}

wl_list_init(&manager->resources);
wl_signal_init(&manager->events.destroy);

manager->display_destroy.notify = handle_display_destroy;
Expand All @@ -423,7 +416,10 @@ void wlr_primary_selection_device_manager_destroy(
}
wlr_signal_emit_safe(&manager->events.destroy, manager);
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);
free(manager);
}