gtk-primary-selection: refactor everything, untie from seat

This commits completely refactors wlr_gtk_primary_selection. The goal is to
remove gtk-primary-selection state from the seat and better handle inert
resources where it makes sense.

wlr_seat_client.primary_selection_devices has been removed and replaced by
wlr_gtk_primary_selection_device. This allows us to make offers inert when the
current selection is replaced.

wlr_seat_set_primary_selection has been removed because it relied on wlr_seat
instead of wlr_gtk_primary_selection_device_manager. A new function,
wlr_gtk_primary_selection_device_manager_set_selection (candidate for the
longest function name in wlroots) has been added. It doesn't take a serial
anymore as serial checking only makes sense for set_selection requests coming
from Wayland clients (serial checking is now done in the Wayland interface
implementation).

Since wlr_gtk_primary_selection_device_manager is now required to set the
selection, a new function wlr_xwayland_set_gtk_primary_selection_device_manager
(candidate number two for longest function name) has been added.

Devices are now made inert when the seat goes away.

Future work includes removing the last primary selection bits from the seat,
mainly wlr_seat.primary_selection_source and wlr_seat.events.primary_selection,
replacing those with new fields in wlr_gtk_primary_selection_device. Or maybe
we could keep those in the seat and replace them with a re-usable interface
(for future zwp_primary_selection_v1 support). We need to think how we'll sync
these three protocols (GTK, X11 and wayland-protocols).

See https://github.com/swaywm/wlroots/issues/1388
master
emersion 6 years ago
parent 05bb440786
commit f001f98cef
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48

@ -14,7 +14,8 @@
struct wlr_gtk_primary_selection_device_manager {
struct wl_global *global;
struct wl_list resources;
struct wl_list resources; // wl_resource_get_link
struct wl_list devices; // wlr_gtk_primary_selection_device::link
struct wl_listener display_destroy;
@ -25,6 +26,28 @@ struct wlr_gtk_primary_selection_device_manager {
void *data;
};
/**
* A device is a per-seat object used to set and get the current selection.
*/
struct wlr_gtk_primary_selection_device {
struct wlr_gtk_primary_selection_device_manager *manager;
struct wlr_seat *seat;
struct wl_list link; // wlr_gtk_primary_selection_device_manager::devices
struct wl_list resources; // wl_resource_get_link
struct wlr_gtk_primary_selection_source *source;
struct wl_list offers; // wlr_gtk_primary_selection_offer::link
struct wl_listener seat_destroy;
struct wl_listener seat_focus_change;
struct wl_listener source_destroy;
void *data;
};
/**
* A source is the sending side of a selection.
*/
struct wlr_gtk_primary_selection_source {
// source metadata
struct wl_array mime_types;
@ -34,9 +57,6 @@ struct wlr_gtk_primary_selection_source {
const char *mime_type, int32_t fd);
void (*cancel)(struct wlr_gtk_primary_selection_source *source);
// source status
struct wlr_seat_client *seat_client;
struct {
struct wl_signal destroy;
} events;
@ -44,9 +64,15 @@ struct wlr_gtk_primary_selection_source {
void *data;
};
/**
* An offer is the receiving side of a selection. When the selection is set,
* offers are created for the currently focused client and can be used to
* initiate the data transfer.
*/
struct wlr_gtk_primary_selection_offer {
struct wl_resource *resource;
struct wlr_gtk_primary_selection_source *source;
struct wl_list link; // wlr_gtk_primary_selection_device::offers
struct wl_listener source_destroy;
@ -58,9 +84,10 @@ struct wlr_gtk_primary_selection_device_manager *
void wlr_gtk_primary_selection_device_manager_destroy(
struct wlr_gtk_primary_selection_device_manager *manager);
void wlr_seat_client_send_gtk_primary_selection(struct wlr_seat_client *seat_client);
void wlr_seat_set_gtk_primary_selection(struct wlr_seat *seat,
struct wlr_gtk_primary_selection_source *source, uint32_t serial);
void wlr_gtk_primary_selection_device_manager_set_selection(
struct wlr_gtk_primary_selection_device_manager *manager,
struct wlr_seat *seat,
struct wlr_gtk_primary_selection_source *source);
void wlr_gtk_primary_selection_source_init(
struct wlr_gtk_primary_selection_source *source);

@ -30,7 +30,6 @@ 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;
@ -168,6 +167,10 @@ struct wlr_seat_keyboard_state {
struct wlr_seat_keyboard_grab *grab;
struct wlr_seat_keyboard_grab *default_grab;
struct {
struct wl_signal focus_change; // wlr_seat_keyboard_focus_change_event
} events;
};
struct wlr_seat_touch_state {
@ -194,6 +197,7 @@ struct wlr_seat {
struct wlr_data_source *selection_source;
uint32_t selection_serial;
// not owned by the seat
struct wlr_gtk_primary_selection_source *primary_selection_source;
uint32_t primary_selection_serial;
@ -208,7 +212,6 @@ struct wlr_seat {
struct wl_listener display_destroy;
struct wl_listener selection_source_destroy;
struct wl_listener primary_selection_source_destroy;
struct wl_listener drag_source_destroy;
struct {
@ -248,6 +251,11 @@ struct wlr_seat_pointer_focus_change_event {
double sx, sy;
};
struct wlr_seat_keyboard_focus_change_event {
struct wlr_seat *seat;
struct wlr_surface *old_surface, *new_surface;
};
/**
* Allocates a new wlr_seat and adds a wl_seat global to the display.
*/

@ -18,6 +18,7 @@
struct wlr_xwm;
struct wlr_xwayland_cursor;
struct wlr_gtk_primary_selection_device_manager;
struct wlr_xwayland {
pid_t pid;
@ -42,13 +43,15 @@ struct wlr_xwayland {
struct wl_display *wl_display;
struct wlr_compositor *compositor;
struct wlr_seat *seat;
struct wl_listener seat_destroy;
struct wlr_gtk_primary_selection_device_manager *gtk_primary_selection;
struct {
struct wl_signal ready;
struct wl_signal new_surface;
} events;
struct wl_listener seat_destroy;
/**
* Add a custom event handler to xwayland. Return 1 if the event was
* handled or 0 to use the default wlr-xwayland handler. wlr-xwayland will
@ -223,6 +226,10 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface,
void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland,
struct wlr_seat *seat);
void wlr_xwayland_set_gtk_primary_selection_device_manager(
struct wlr_xwayland *xwayland,
struct wlr_gtk_primary_selection_device_manager *manager);
bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface);
struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface(

@ -955,11 +955,18 @@ 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_gtk_primary_selection_device_manager_create(server->wl_display);
desktop->idle = wlr_idle_create(server->wl_display);
desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display);
desktop->primary_selection_device_manager =
wlr_gtk_primary_selection_device_manager_create(server->wl_display);
#if WLR_HAS_XWAYLAND
if (desktop->xwayland != NULL) {
wlr_xwayland_set_gtk_primary_selection_device_manager(
desktop->xwayland, desktop->primary_selection_device_manager);
}
#endif
desktop->input_inhibit =
wlr_input_inhibit_manager_create(server->wl_display);
desktop->input_inhibit_activate.notify = input_inhibit_activate;

@ -6,7 +6,6 @@
#include <wayland-server.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_gtk_primary_selection.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/util/log.h>
#include "types/wlr_seat.h"
@ -88,10 +87,6 @@ static void seat_client_handle_resource_destroy(
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);
@ -138,7 +133,6 @@ static void seat_handle_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_signal_init(&seat_client->events.destroy);
wl_list_insert(&wlr_seat->clients, &seat_client->link);
@ -167,11 +161,6 @@ void wlr_seat_destroy(struct wlr_seat *seat) {
wlr_data_source_cancel(seat->selection_source);
seat->selection_source = NULL;
}
if (seat->primary_selection_source) {
wl_list_remove(&seat->primary_selection_source_destroy.link);
seat->primary_selection_source->cancel(seat->primary_selection_source);
seat->primary_selection_source = NULL;
}
struct wlr_seat_client *client, *tmp;
wl_list_for_each_safe(client, tmp, &seat->clients, link) {
@ -243,6 +232,8 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
seat->keyboard_state.seat = seat;
wl_list_init(&seat->keyboard_state.surface_destroy.link);
wl_signal_init(&seat->keyboard_state.events.focus_change);
// touch state
struct wlr_seat_touch_grab *touch_grab =
calloc(1, sizeof(struct wlr_seat_touch_grab));

@ -273,7 +273,6 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat,
wl_array_release(&keys);
wlr_seat_client_send_selection(client);
wlr_seat_client_send_gtk_primary_selection(client);
}
// reinitialize the focus destroy events
@ -294,6 +293,13 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat,
// as it targets seat->keyboard_state.focused_client
wlr_seat_keyboard_send_modifiers(seat, modifiers);
}
struct wlr_seat_keyboard_focus_change_event event = {
.seat = seat,
.old_surface = focused_surface,
.new_surface = surface,
};
wlr_signal_emit_safe(&seat->keyboard_state.events.focus_change, &event);
}
void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,

@ -22,7 +22,8 @@ static struct wlr_gtk_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_gtk_primary_selection_offer *offer = offer_from_resource(resource);
struct wlr_gtk_primary_selection_offer *offer =
offer_from_resource(resource);
if (offer == NULL) {
close(fd);
return;
@ -52,7 +53,8 @@ static void offer_destroy(struct wlr_gtk_primary_selection_offer *offer) {
}
static void offer_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_gtk_primary_selection_offer *offer = offer_from_resource(resource);
struct wlr_gtk_primary_selection_offer *offer =
offer_from_resource(resource);
offer_destroy(offer);
}
@ -63,27 +65,8 @@ static void offer_handle_source_destroy(struct wl_listener *listener,
offer_destroy(offer);
}
struct client_data_source {
struct wlr_gtk_primary_selection_source source;
struct wl_resource *resource;
};
static void client_source_send(struct wlr_gtk_primary_selection_source *wlr_source,
const char *mime_type, int32_t fd) {
struct client_data_source *source = (struct client_data_source *)wlr_source;
gtk_primary_selection_source_send_send(source->resource, mime_type, fd);
close(fd);
}
static void client_source_cancel(
struct wlr_gtk_primary_selection_source *wlr_source) {
struct client_data_source *source = (struct client_data_source *)wlr_source;
gtk_primary_selection_source_send_cancelled(source->resource);
}
static void source_send_offer(struct wlr_gtk_primary_selection_source *source,
struct wl_resource *device_resource) {
static void offer_create(struct wl_resource *device_resource,
struct wlr_gtk_primary_selection_source *source) {
struct wlr_gtk_primary_selection_offer *offer =
calloc(1, sizeof(struct wlr_gtk_primary_selection_offer));
if (offer == NULL) {
@ -103,6 +86,8 @@ static void source_send_offer(struct wlr_gtk_primary_selection_source *source,
wl_resource_set_implementation(offer->resource, &offer_impl, offer,
offer_handle_resource_destroy);
offer->source = source;
offer->source_destroy.notify = offer_handle_source_destroy;
wl_signal_add(&source->events.destroy, &offer->source_destroy);
@ -114,12 +99,31 @@ static void source_send_offer(struct wlr_gtk_primary_selection_source *source,
gtk_primary_selection_offer_send_offer(offer->resource, *p);
}
offer->source = source;
gtk_primary_selection_device_send_selection(device_resource,
offer->resource);
}
struct client_data_source {
struct wlr_gtk_primary_selection_source source;
struct wl_resource *resource;
};
static void client_source_send(
struct wlr_gtk_primary_selection_source *wlr_source,
const char *mime_type, int32_t fd) {
struct client_data_source *source = (struct client_data_source *)wlr_source;
gtk_primary_selection_source_send_send(source->resource, mime_type, fd);
close(fd);
}
static void client_source_cancel(
struct wlr_gtk_primary_selection_source *wlr_source) {
struct client_data_source *source = (struct client_data_source *)wlr_source;
gtk_primary_selection_source_send_cancelled(source->resource);
// TODO: make the source resource inert
}
static const struct gtk_primary_selection_source_interface source_impl;
static struct client_data_source *client_data_source_from_resource(
@ -164,121 +168,207 @@ static void source_resource_handle_destroy(struct wl_resource *resource) {
}
void wlr_seat_client_send_gtk_primary_selection(
struct wlr_seat_client *seat_client) {
if (wl_list_empty(&seat_client->primary_selection_devices)) {
static const struct gtk_primary_selection_device_interface device_impl;
static struct wlr_gtk_primary_selection_device *device_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource,
&gtk_primary_selection_device_interface, &device_impl));
return wl_resource_get_user_data(resource);
}
static void device_handle_set_selection(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *source_resource,
uint32_t serial) {
struct wlr_gtk_primary_selection_device *device =
device_from_resource(resource);
if (device == NULL) {
return;
}
struct wlr_gtk_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);
struct client_data_source *source = NULL;
if (source_resource != NULL) {
source = client_data_source_from_resource(source_resource);
}
// TODO: improve serial checking
struct wlr_seat *seat = device->seat;
if (seat->primary_selection_serial > 0 &&
seat->primary_selection_serial - serial < UINT32_MAX / 2) {
return;
}
seat->primary_selection_serial = serial;
wlr_gtk_primary_selection_device_manager_set_selection(device->manager,
seat, &source->source);
}
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;
static void device_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
if (seat_client && seat->keyboard_state.focused_surface) {
struct wl_resource *resource;
wl_resource_for_each(resource, &seat_client->primary_selection_devices) {
static const struct gtk_primary_selection_device_interface device_impl = {
.set_selection = device_handle_set_selection,
.destroy = device_handle_destroy,
};
static void device_handle_resource_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
}
static void device_resource_send_selection(struct wl_resource *resource,
struct wlr_gtk_primary_selection_source *source) {
assert(device_from_resource(resource) != NULL);
if (source != NULL) {
offer_create(resource, source);
} else {
gtk_primary_selection_device_send_selection(resource, NULL);
}
}
seat->primary_selection_source = NULL;
static void device_send_selection(
struct wlr_gtk_primary_selection_device *device) {
struct wlr_seat_client *seat_client =
device->seat->keyboard_state.focused_client;
wlr_signal_emit_safe(&seat->events.primary_selection, seat);
struct wl_resource *resource;
wl_resource_for_each(resource, &device->resources) {
if (wl_resource_get_client(resource) == seat_client->client) {
device_resource_send_selection(resource, device->source);
}
}
}
static void device_handle_source_destroy(struct wl_listener *listener,
void *data);
void wlr_seat_set_gtk_primary_selection(struct wlr_seat *seat,
struct wlr_gtk_primary_selection_source *source, uint32_t serial) {
if (source) {
static void device_set_selection(
struct wlr_gtk_primary_selection_device *device,
struct wlr_gtk_primary_selection_source *source) {
if (source != NULL) {
assert(source->send);
assert(source->cancel);
}
if (seat->primary_selection_source &&
seat->primary_selection_serial - serial < UINT32_MAX / 2) {
return;
if (device->source != NULL) {
wl_list_remove(&device->source_destroy.link);
device->source->cancel(device->source);
device->source = NULL;
}
// 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);
seat->primary_selection_source = NULL;
struct wlr_gtk_primary_selection_offer *offer, *tmp;
wl_list_for_each_safe(offer, tmp, &device->offers, link) {
offer_destroy(offer);
}
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_gtk_primary_selection(focused_client);
device->source = source;
if (source != NULL) {
device->source_destroy.notify = device_handle_source_destroy;
wl_signal_add(&source->events.destroy, &device->source_destroy);
}
wlr_signal_emit_safe(&seat->events.primary_selection, seat);
device_send_selection(device);
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);
}
struct wlr_seat *seat = device->seat;
// TODO: remove these from wlr_seat
seat->primary_selection_source = source;
wlr_signal_emit_safe(&seat->events.primary_selection, seat);
}
static void device_destroy(struct wlr_gtk_primary_selection_device *device);
static const struct gtk_primary_selection_device_interface device_impl;
static void device_handle_seat_destroy(struct wl_listener *listener,
void *data) {
struct wlr_gtk_primary_selection_device *device =
wl_container_of(listener, device, seat_destroy);
device_destroy(device);
}
static struct wlr_seat_client *seat_client_from_device_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource,
&gtk_primary_selection_device_interface, &device_impl));
return wl_resource_get_user_data(resource);
static void device_handle_seat_focus_change(struct wl_listener *listener,
void *data) {
struct wlr_gtk_primary_selection_device *device =
wl_container_of(listener, device, seat_focus_change);
device_send_selection(device);
}
static void device_handle_set_selection(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *source_resource,
uint32_t serial) {
struct client_data_source *source = NULL;
if (source_resource != NULL) {
source = client_data_source_from_resource(source_resource);
static void device_handle_source_destroy(struct wl_listener *listener,
void *data) {
struct wlr_gtk_primary_selection_device *device =
wl_container_of(listener, device, source_destroy);
wl_list_remove(&device->source_destroy.link);
device->source = NULL;
device_send_selection(device);
}
struct wlr_seat_client *seat_client =
seat_client_from_device_resource(resource);
static struct wlr_gtk_primary_selection_device *get_or_create_device(
struct wlr_gtk_primary_selection_device_manager *manager,
struct wlr_seat *seat) {
struct wlr_gtk_primary_selection_device *device;
wl_list_for_each(device, &manager->devices, link) {
if (device->seat == seat) {
return device;
}
}
struct wlr_gtk_primary_selection_source *wlr_source =
(struct wlr_gtk_primary_selection_source *)source;
wlr_seat_set_gtk_primary_selection(seat_client->seat, wlr_source, serial);
device = calloc(1, sizeof(struct wlr_gtk_primary_selection_device));
if (device == NULL) {
return NULL;
}
device->manager = manager;
device->seat = seat;
static void device_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
wl_list_init(&device->resources);
wl_list_insert(&manager->devices, &device->link);
wl_list_init(&device->offers);
device->seat_destroy.notify = device_handle_seat_destroy;
wl_signal_add(&seat->events.destroy, &device->seat_destroy);
device->seat_focus_change.notify = device_handle_seat_focus_change;
wl_signal_add(&seat->keyboard_state.events.focus_change,
&device->seat_focus_change);
return device;
}
static const struct gtk_primary_selection_device_interface device_impl = {
.set_selection = device_handle_set_selection,
.destroy = device_handle_destroy,
};
static void device_destroy(struct wlr_gtk_primary_selection_device *device) {
if (device == NULL) {
return;
}
wl_list_remove(&device->link);
wl_list_remove(&device->seat_destroy.link);
wl_list_remove(&device->seat_focus_change.link);
struct wlr_gtk_primary_selection_offer *offer, *offer_tmp;
wl_list_for_each_safe(offer, offer_tmp, &device->offers, link) {
offer_destroy(offer);
}
struct wl_resource *resource, *resource_tmp;
wl_resource_for_each_safe(resource, resource_tmp, &device->resources) {
// Make the resource inert
wl_resource_set_user_data(resource, NULL);
static void device_resource_handle_destroy(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
struct wl_list *link = wl_resource_get_link(resource);
wl_list_remove(link);
wl_list_init(link);
}
free(device);
}
static const struct gtk_primary_selection_device_manager_interface
device_manager_impl;
struct wlr_gtk_primary_selection_device_manager *manager_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource,
&gtk_primary_selection_device_manager_interface, &device_manager_impl));
return wl_resource_get_user_data(resource);
}
void wlr_gtk_primary_selection_source_init(
struct wlr_gtk_primary_selection_source *source) {
wl_array_init(&source->mime_types);
@ -310,7 +400,7 @@ static void device_manager_handle_create_source(struct wl_client *client,
}
wlr_gtk_primary_selection_source_init(&source->source);
int version = wl_resource_get_version(manager_resource);
uint32_t version = wl_resource_get_version(manager_resource);
source->resource = wl_resource_create(client,
&gtk_primary_selection_source_interface, version, id);
if (source->resource == NULL) {
@ -330,6 +420,15 @@ void device_manager_handle_get_device(struct wl_client *client,
struct wl_resource *seat_resource) {
struct wlr_seat_client *seat_client =
wlr_seat_client_from_resource(seat_resource);
struct wlr_gtk_primary_selection_device_manager *manager =
manager_from_resource(manager_resource);
struct wlr_gtk_primary_selection_device *device =
get_or_create_device(manager, seat_client->seat);
if (device == NULL) {
wl_resource_post_no_memory(manager_resource);
return;
}
uint32_t version = wl_resource_get_version(manager_resource);
struct wl_resource *resource = wl_resource_create(client,
@ -338,10 +437,13 @@ void device_manager_handle_get_device(struct wl_client *client,
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));
wl_resource_set_implementation(resource, &device_impl, device,
device_handle_resource_destroy);
wl_list_insert(&device->resources, wl_resource_get_link(resource));
if (device->seat->keyboard_state.focused_client == seat_client) {
device_resource_send_selection(resource, device->source);
}
}
static void device_manager_handle_destroy(struct wl_client *client,
@ -362,6 +464,18 @@ static void device_manager_handle_resource_destroy(
}
void wlr_gtk_primary_selection_device_manager_set_selection(
struct wlr_gtk_primary_selection_device_manager *manager,
struct wlr_seat *seat,
struct wlr_gtk_primary_selection_source *source) {
struct wlr_gtk_primary_selection_device *device =
get_or_create_device(manager, seat);
if (device == NULL) {
return;
}
device_set_selection(device, source);
}
static void primary_selection_device_manager_bind(struct wl_client *client,
void *data, uint32_t version, uint32_t id) {
struct wlr_gtk_primary_selection_device_manager *manager = data;
@ -401,6 +515,7 @@ struct wlr_gtk_primary_selection_device_manager *
}
wl_list_init(&manager->resources);
wl_list_init(&manager->devices);
wl_signal_init(&manager->events.destroy);
manager->display_destroy.notify = handle_display_destroy;

@ -365,9 +365,9 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) {
bool ok = source_get_targets(selection, &source->base.mime_types,
&source->mime_types_atoms);
if (ok) {
wlr_seat_set_gtk_primary_selection(xwm->seat, &source->base,
wl_display_next_serial(xwm->xwayland->wl_display));
if (ok && xwm->xwayland->gtk_primary_selection) {
wlr_gtk_primary_selection_device_manager_set_selection(
xwm->xwayland->gtk_primary_selection, xwm->seat, &source->base);
} else {
source->base.cancel(&source->base);
}
@ -423,9 +423,10 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
if (selection == &xwm->clipboard_selection) {
wlr_seat_set_selection(xwm->seat, NULL,
wl_display_next_serial(xwm->xwayland->wl_display));
} else if (selection == &xwm->primary_selection) {
wlr_seat_set_gtk_primary_selection(xwm->seat, NULL,
wl_display_next_serial(xwm->xwayland->wl_display));
} else if (selection == &xwm->primary_selection &&
xwm->xwayland->gtk_primary_selection) {
wlr_gtk_primary_selection_device_manager_set_selection(
xwm->xwayland->gtk_primary_selection, xwm->seat, NULL);
} else if (selection == &xwm->dnd_selection) {
// TODO: DND
} else {

@ -228,11 +228,12 @@ void xwm_selection_finish(struct wlr_xwm *xwm) {
wlr_seat_set_selection(xwm->seat, NULL,
wl_display_next_serial(xwm->xwayland->wl_display));
}
if (xwm->seat->primary_selection_source &&
if (xwm->xwayland->gtk_primary_selection &&
xwm->seat->primary_selection_source &&
primary_selection_source_is_xwayland(
xwm->seat->primary_selection_source)) {
wlr_seat_set_gtk_primary_selection(xwm->seat, NULL,
wl_display_next_serial(xwm->xwayland->wl_display));
wlr_gtk_primary_selection_device_manager_set_selection(
xwm->xwayland->gtk_primary_selection, xwm->seat, NULL);
}
wlr_xwayland_set_seat(xwm->xwayland, NULL);
}

@ -505,3 +505,9 @@ void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland,
xwayland->seat_destroy.notify = xwayland_handle_seat_destroy;
wl_signal_add(&seat->events.destroy, &xwayland->seat_destroy);
}
void wlr_xwayland_set_gtk_primary_selection_device_manager(
struct wlr_xwayland *xwayland,
struct wlr_gtk_primary_selection_device_manager *manager) {
xwayland->gtk_primary_selection = manager;
}

Loading…
Cancel
Save