Skip to content

Commit

Permalink
data-control: Ignore our own offers via custom MIME type
Browse files Browse the repository at this point in the history
Offer a custom MIME type (unique per wayvnc_client) when setting the
selections of the Wayland clipboard which we can detect when processing
incoming Wayland selections, and avoid unnecessarily echoing an
incoming VNC client clipboard update back to the same VNC client.

It would be useful if when a wlr_data_control_device sends
set_selection, the selection event received could have an enum
argument value describing that the wlr_data_control_offer in the id
argument is associated with a wlr_data_control_source passed to
set_selection by the same wlr_data_control_device.

https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/issues/111
swaywm/wlroots#2406
  • Loading branch information
layercak3 authored and any1 committed Sep 16, 2024
1 parent b9e905b commit 34a1d25
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
3 changes: 3 additions & 0 deletions include/data-control.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ struct data_control {
struct zwlr_data_control_source_v1* selection;
struct zwlr_data_control_source_v1* primary_selection;
struct zwlr_data_control_offer_v1* offer;
bool is_own_offer;
const char* mime_type;
/* x-wayvnc-client-(8 hexadecimal digits) + \0 */
char custom_mime_type_name[32];
char* cb_data;
size_t cb_len;
};
Expand Down
42 changes: 33 additions & 9 deletions src/data-control.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#include "data-control.h"

static const char custom_mime_type_data[] = "wayvnc";

struct receive_context {
struct data_control* data_control;
struct zwlr_data_control_offer_v1* offer;
Expand Down Expand Up @@ -124,11 +126,15 @@ static void data_control_offer(void* data,
{
struct data_control* self = data;

if (strcmp(mime_type, self->custom_mime_type_name) == 0) {
self->is_own_offer = true;
return;
}

if (self->offer)
return;
if (strcmp(mime_type, self->mime_type) != 0) {
if (strcmp(mime_type, self->mime_type) != 0)
return;
}

self->offer = zwlr_data_control_offer_v1;
}
Expand All @@ -153,9 +159,13 @@ static void data_control_device_selection(void* data,
{
struct data_control* self = data;
if (id && self->offer == id) {
receive_data(data, id);
if (!self->is_own_offer)
receive_data(data, id);
else
zwlr_data_control_offer_v1_destroy(self->offer);
self->offer = NULL;
}
self->is_own_offer = false;
}

static void data_control_device_finished(void* data,
Expand All @@ -170,10 +180,13 @@ static void data_control_device_primary_selection(void* data,
{
struct data_control* self = data;
if (id && self->offer == id) {
receive_data(data, id);
if (!self->is_own_offer)
receive_data(data, id);
else
zwlr_data_control_offer_v1_destroy(self->offer);
self->offer = NULL;
return;
}
self->is_own_offer = false;
}

static struct zwlr_data_control_device_v1_listener data_control_device_listener = {
Expand All @@ -196,10 +209,15 @@ data_control_source_send(void* data,

assert(d);

ret = write(fd, d, len);

if (ret < (int)len)
nvnc_log(NVNC_LOG_ERROR, "write from clipboard incomplete");
if (strcmp(mime_type, self->custom_mime_type_name) == 0) {
ret = write(fd, custom_mime_type_data, strlen(custom_mime_type_data));
if (ret < (int)strlen(custom_mime_type_data))
nvnc_log(NVNC_LOG_ERROR, "custom mime type data write incomplete");
} else {
ret = write(fd, d, len);
if (ret < (int)len)
nvnc_log(NVNC_LOG_ERROR, "write from clipboard incomplete");
}

close(fd);
}
Expand Down Expand Up @@ -235,6 +253,7 @@ static struct zwlr_data_control_source_v1* set_selection(struct data_control* se

zwlr_data_control_source_v1_add_listener(selection, &data_control_source_listener, self);
zwlr_data_control_source_v1_offer(selection, self->mime_type);
zwlr_data_control_source_v1_offer(selection, self->custom_mime_type_name);

if (primary)
zwlr_data_control_device_v1_set_primary_selection(self->device, selection);
Expand All @@ -252,9 +271,14 @@ void data_control_init(struct data_control* self, struct wl_display* wl_display,
zwlr_data_control_device_v1_add_listener(self->device, &data_control_device_listener, self);
self->selection = NULL;
self->primary_selection = NULL;
self->offer = NULL;
self->is_own_offer = false;
self->cb_data = NULL;
self->cb_len = 0;
self->mime_type = "text/plain;charset=utf-8";
snprintf(self->custom_mime_type_name,
sizeof(self->custom_mime_type_name),
"x-wayvnc-client-%08x", (unsigned int)rand());
}

void data_control_destroy(struct data_control* self)
Expand Down
3 changes: 3 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
Expand Down Expand Up @@ -2005,6 +2006,8 @@ int main(int argc, char* argv[])
self.disable_input = disable_input;
self.use_transient_seat = use_transient_seat;

srand(time(NULL));

struct aml* aml = aml_new();
if (!aml)
goto failure;
Expand Down

0 comments on commit 34a1d25

Please sign in to comment.