data-device, primary-selection: add request_set_selection

This makes compositors able to block and/or customize set_selection requests
coming from clients. For instance, it's possible for a compositor to disable
rich selection content (by removing all MIME types except text/plain). This
commit implements the design proposed in [1].

Two new events are added to wlr_seat: request_set_selection and
request_set_primary_selection. Compositors need to listen to these events and
either destroy the source or effectively set the selection.

Fixes https://github.com/swaywm/wlroots/issues/1138

[1]: https://github.com/swaywm/wlroots/issues/1367#issuecomment-442403454
This commit is contained in:
emersion 2018-11-29 19:30:04 +01:00
parent c41d01306d
commit 4cb0697e57
15 changed files with 142 additions and 63 deletions

View file

@ -32,13 +32,13 @@ static void data_device_set_selection(struct wl_client *client,
source = client_data_source_from_resource(source_resource);
}
struct wlr_data_source *wlr_source =
source != NULL ? &source->source : NULL;
wlr_seat_set_selection(seat_client->seat, wlr_source, serial);
if (source != NULL) {
source->finalized = true;
}
struct wlr_data_source *wlr_source =
source != NULL ? &source->source : NULL;
wlr_seat_request_set_selection(seat_client->seat, wlr_source, serial);
}
static void data_device_start_drag(struct wl_client *client,
@ -116,7 +116,23 @@ void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {
}
}
static void seat_client_selection_source_destroy(
void wlr_seat_request_set_selection(struct wlr_seat *seat,
struct wlr_data_source *source, uint32_t serial) {
if (seat->selection_source &&
seat->selection_serial - serial < UINT32_MAX / 2) {
wlr_log(WLR_DEBUG, "Rejecting set_selection request, invalid serial "
"(%"PRIu32" <= %"PRIu32")", serial, seat->selection_serial);
return;
}
struct wlr_seat_request_set_selection_event event = {
.source = source,
.serial = serial,
};
wlr_signal_emit_safe(&seat->events.request_set_selection, &event);
}
static void seat_handle_selection_source_destroy(
struct wl_listener *listener, void *data) {
struct wlr_seat *seat =
wl_container_of(listener, seat, selection_source_destroy);
@ -132,16 +148,11 @@ static void seat_client_selection_source_destroy(
}
}
wlr_signal_emit_safe(&seat->events.selection, seat);
wlr_signal_emit_safe(&seat->events.set_selection, seat);
}
void wlr_seat_set_selection(struct wlr_seat *seat,
struct wlr_data_source *source, uint32_t serial) {
if (seat->selection_source &&
seat->selection_serial - serial < UINT32_MAX / 2) {
return;
}
if (seat->selection_source) {
wl_list_remove(&seat->selection_source_destroy.link);
wlr_data_source_cancel(seat->selection_source);
@ -153,19 +164,18 @@ void wlr_seat_set_selection(struct wlr_seat *seat,
struct wlr_seat_client *focused_client =
seat->keyboard_state.focused_client;
if (focused_client) {
wlr_seat_client_send_selection(focused_client);
}
wlr_signal_emit_safe(&seat->events.selection, seat);
if (source) {
seat->selection_source_destroy.notify =
seat_client_selection_source_destroy;
seat_handle_selection_source_destroy;
wl_signal_add(&source->events.destroy,
&seat->selection_source_destroy);
}
wlr_signal_emit_safe(&seat->events.set_selection, seat);
}

View file

@ -274,8 +274,10 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
wl_signal_init(&seat->events.request_set_cursor);
wl_signal_init(&seat->events.selection);
wl_signal_init(&seat->events.primary_selection);
wl_signal_init(&seat->events.request_set_selection);
wl_signal_init(&seat->events.set_selection);
wl_signal_init(&seat->events.request_set_primary_selection);
wl_signal_init(&seat->events.set_primary_selection);
wl_signal_init(&seat->events.pointer_grab_begin);
wl_signal_init(&seat->events.pointer_grab_end);

View file

@ -184,9 +184,8 @@ static void control_handle_set_selection(struct wl_client *client,
}
struct wlr_data_source *wlr_source = source ? &source->source : NULL;
struct wl_display *display = wl_client_get_display(client);
wlr_seat_set_selection(device->seat, wlr_source,
wl_display_next_serial(display));
wlr_seat_request_set_selection(device->seat, wlr_source,
wl_display_next_serial(device->seat->display));
}
static void control_handle_destroy(struct wl_client *client,
@ -232,10 +231,10 @@ static void control_handle_seat_destroy(struct wl_listener *listener,
wlr_data_control_device_v1_destroy(device);
}
static void control_handle_seat_selection(struct wl_listener *listener,
static void control_handle_seat_set_selection(struct wl_listener *listener,
void *data) {
struct wlr_data_control_device_v1 *device =
wl_container_of(listener, device, seat_selection);
wl_container_of(listener, device, seat_set_selection);
control_send_selection(device);
}
@ -250,7 +249,7 @@ void wlr_data_control_device_v1_destroy(struct wlr_data_control_device_v1 *devic
wl_resource_set_user_data(device->selection_offer_resource, NULL);
}
wl_list_remove(&device->seat_destroy.link);
wl_list_remove(&device->seat_selection.link);
wl_list_remove(&device->seat_set_selection.link);
wl_list_remove(&device->link);
free(device);
}
@ -319,8 +318,9 @@ static void manager_handle_get_data_device(struct wl_client *client,
device->seat_destroy.notify = control_handle_seat_destroy;
wl_signal_add(&device->seat->events.destroy, &device->seat_destroy);
device->seat_selection.notify = control_handle_seat_selection;
wl_signal_add(&device->seat->events.selection, &device->seat_selection);
device->seat_set_selection.notify = control_handle_seat_set_selection;
wl_signal_add(&device->seat->events.set_selection,
&device->seat_set_selection);
wl_list_insert(&manager->devices, &device->link);
wlr_signal_emit_safe(&manager->events.new_device, device);

View file

@ -208,7 +208,7 @@ static void device_handle_set_selection(struct wl_client *client,
source = &client_source->source;
}
wlr_seat_set_primary_selection(device->seat, source, serial);
wlr_seat_request_set_primary_selection(device->seat, source, serial);
}
static void device_handle_destroy(struct wl_client *client,
@ -272,10 +272,10 @@ static void device_handle_seat_focus_change(struct wl_listener *listener,
device_send_selection(device);
}
static void device_handle_seat_primary_selection(struct wl_listener *listener,
void *data) {
static void device_handle_seat_set_primary_selection(
struct wl_listener *listener, void *data) {
struct wlr_gtk_primary_selection_device *device =
wl_container_of(listener, device, seat_primary_selection);
wl_container_of(listener, device, seat_set_primary_selection);
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe(resource, tmp, &device->offers) {
@ -314,10 +314,10 @@ static struct wlr_gtk_primary_selection_device *get_or_create_device(
wl_signal_add(&seat->keyboard_state.events.focus_change,
&device->seat_focus_change);
device->seat_primary_selection.notify =
device_handle_seat_primary_selection;
wl_signal_add(&seat->events.primary_selection,
&device->seat_primary_selection);
device->seat_set_primary_selection.notify =
device_handle_seat_set_primary_selection;
wl_signal_add(&seat->events.set_primary_selection,
&device->seat_set_primary_selection);
return device;
}
@ -329,7 +329,7 @@ static void device_destroy(struct wlr_gtk_primary_selection_device *device) {
wl_list_remove(&device->link);
wl_list_remove(&device->seat_destroy.link);
wl_list_remove(&device->seat_focus_change.link);
wl_list_remove(&device->seat_primary_selection.link);
wl_list_remove(&device->seat_set_primary_selection.link);
struct wl_resource *resource, *resource_tmp;
wl_resource_for_each_safe(resource, resource_tmp, &device->offers) {
destroy_offer(resource);

View file

@ -41,13 +41,30 @@ void wlr_primary_selection_source_send(
}
void wlr_seat_request_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) {
wlr_log(WLR_DEBUG, "Rejecting set_primary_selection request, "
"invalid serial (%"PRIu32" <= %"PRIu32")",
serial, seat->primary_selection_serial);
return;
}
struct wlr_seat_request_set_primary_selection_event event = {
.source = source,
.serial = serial,
};
wlr_signal_emit_safe(&seat->events.request_set_primary_selection, &event);
}
static void seat_handle_primary_selection_source_destroy(
struct wl_listener *listener, void *data) {
struct wlr_seat *seat =
wl_container_of(listener, seat, primary_selection_source_destroy);
wl_list_remove(&seat->primary_selection_source_destroy.link);
seat->primary_selection_source = NULL;
wlr_signal_emit_safe(&seat->events.primary_selection, seat);
wlr_signal_emit_safe(&seat->events.set_primary_selection, seat);
}
void wlr_seat_set_primary_selection(struct wlr_seat *seat,
@ -75,5 +92,5 @@ void wlr_seat_set_primary_selection(struct wlr_seat *seat,
&seat->primary_selection_source_destroy);
}
wlr_signal_emit_safe(&seat->events.primary_selection, seat);
wlr_signal_emit_safe(&seat->events.set_primary_selection, seat);
}