[PATCH weston 16/16] xwayland: Proxy selection for copy-paste
Tiago Vignatti
tiago.vignatti at intel.com
Wed Dec 12 07:26:28 PST 2012
This commit implements the selection proxy to connect XWayland copy-paste with
the Wayland one, bringing back the last remaining feature we had before the
xwm was split as a client (#2 selection support).
It connects the clipboard also for dealing with clients that go away. Worth to
note that this only brings the needed implementation for porting selection to
weston-xwm client and, that being said, I'm sure there are corn cases still to
be solved.
For testing, I'm opening one X gedit and one weston-terminal and then
selecting text and performing copy-paste on both directions.
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
clients/Makefile.am | 1 +
clients/xwm-selection.c | 222 ++++++++++++++++-------------------------
clients/xwm.c | 35 ++++---
clients/xwm.h | 30 ++++--
protocol/xserver.xml | 18 +++-
src/xwayland/window-manager.c | 67 +++++++++++--
src/xwayland/xwayland.h | 1 +
7 files changed, 206 insertions(+), 168 deletions(-)
diff --git a/clients/Makefile.am b/clients/Makefile.am
index d2eb4c3..4e9c260 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -171,6 +171,7 @@ weston_tablet_shell_LDADD = $(toolkit_libs)
weston_xwm_SOURCES = \
xwm.h \
xwm.c \
+ xwm-selection.c \
xserver-client-protocol.h \
xserver-protocol.c
weston_xwm_LDADD = $(toolkit_libs)
diff --git a/clients/xwm-selection.c b/clients/xwm-selection.c
index f31afde..f93392b 100644
--- a/clients/xwm-selection.c
+++ b/clients/xwm-selection.c
@@ -26,14 +26,17 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/epoll.h>
-#include "xwayland.h"
-#include "window-manager.h"
+#include <wayland-client.h>
+#include "xserver-client-protocol.h"
+#include "xwm.h"
-static int
-xwm_write_property(int fd, uint32_t mask, void *data)
+static void
+xwm_write_property(struct task *task, uint32_t events)
{
- struct xwm_wm *wm = data;
+ struct xwm_wm *wm =
+ container_of(task, struct xwm_wm, selection_write_task);
unsigned char *property;
int len, remainder;
@@ -41,13 +44,14 @@ xwm_write_property(int fd, uint32_t mask, void *data)
remainder = xcb_get_property_value_length(wm->property_reply) -
wm->property_start;
- len = write(fd, property + wm->property_start, remainder);
+ len = write(wm->data_source_fd, property + wm->property_start,
+ remainder);
if (len == -1) {
free(wm->property_reply);
- wl_event_source_remove(wm->property_source);
- close(fd);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
+ close(wm->data_source_fd);
fprintf(stderr, "write error to target fd: %m\n");
- return 1;
+ return;
}
fprintf(stderr, "wrote %d (chunk size %d) of %d bytes\n",
@@ -57,7 +61,7 @@ xwm_write_property(int fd, uint32_t mask, void *data)
wm->property_start += len;
if (len == remainder) {
free(wm->property_reply);
- wl_event_source_remove(wm->property_source);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
if (wm->incr) {
xcb_delete_property(wm->conn,
@@ -65,11 +69,9 @@ xwm_write_property(int fd, uint32_t mask, void *data)
wm->atom.wl_selection);
} else {
fprintf(stderr, "transfer complete\n");
- close(fd);
+ close(wm->data_source_fd);
}
}
-
- return 1;
}
static void
@@ -92,12 +94,9 @@ xwm_get_incr_chunk(struct xwm_wm *wm)
if (xcb_get_property_value_length(reply) > 0) {
wm->property_start = 0;
- wm->property_source =
- wl_event_loop_add_fd(wm->server->loop,
- wm->data_source_fd,
- WL_EVENT_WRITABLE,
- xwm_write_property,
- wm);
+ wm->selection_write_task.run = xwm_write_property;
+ display_watch_fd(wm->display, wm->data_source_fd,
+ EPOLLOUT, &wm->selection_write_task);
wm->property_reply = reply;
} else {
fprintf(stderr, "transfer complete\n");
@@ -106,23 +105,17 @@ xwm_get_incr_chunk(struct xwm_wm *wm)
}
}
-struct x11_data_source {
- struct wl_data_source base;
- struct xwm_wm *wm;
-};
-
static void
-data_source_accept(struct wl_data_source *source,
- uint32_t time, const char *mime_type)
+data_source_accept(void *data, struct wl_data_source *source,
+ const char *mime_type)
{
}
static void
-data_source_send(struct wl_data_source *base,
+data_source_send(void *data, struct wl_data_source *source,
const char *mime_type, int32_t fd)
{
- struct x11_data_source *source = (struct x11_data_source *) base;
- struct xwm_wm *wm = source->wm;
+ struct xwm_wm *wm = data;
if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
/* Get data for the utf8_string target */
@@ -141,21 +134,25 @@ data_source_send(struct wl_data_source *base,
}
static void
-data_source_cancel(struct wl_data_source *source)
+data_source_cancel(void *data, struct wl_data_source *source)
{
}
+static const struct wl_data_source_listener data_source_listener = {
+ data_source_accept,
+ data_source_send,
+ data_source_cancel
+};
+
static void
xwm_get_selection_targets(struct xwm_wm *wm)
{
- struct x11_data_source *source;
- struct weston_compositor *compositor;
- struct weston_seat *seat = xwm_pick_seat(wm);
xcb_get_property_cookie_t cookie;
xcb_get_property_reply_t *reply;
xcb_atom_t *value;
- char **p;
uint32_t i;
+ int has_text_plain = 0;
+ struct xwm *xwm = wm->xwm;
cookie = xcb_get_property(wm->conn,
1, /* delete */
@@ -173,33 +170,23 @@ xwm_get_selection_targets(struct xwm_wm *wm)
free(reply);
return;
}
-
- source = malloc(sizeof *source);
- if (source == NULL)
- return;
-
- wl_signal_init(&source->base.resource.destroy_signal);
- source->base.accept = data_source_accept;
- source->base.send = data_source_send;
- source->base.cancel = data_source_cancel;
- source->base.resource.data = source;
- source->wm = wm;
-
- wl_array_init(&source->base.mime_types);
value = xcb_get_property_value(reply);
for (i = 0; i < reply->value_len; i++) {
- if (value[i] == wm->atom.utf8_string) {
- p = wl_array_add(&source->base.mime_types, sizeof *p);
- if (p)
- *p = strdup("text/plain;charset=utf-8");
- }
+ if (value[i] == wm->atom.utf8_string)
+ has_text_plain = 1;
}
+ free(reply);
- compositor = wm->server->compositor;
- wl_seat_set_selection(&seat->seat, &source->base,
- wl_display_next_serial(compositor->wl_display));
+ if (!has_text_plain)
+ return;
- free(reply);
+ wm->selection =
+ wl_data_device_manager_create_data_source(xwm->data_device_manager);
+ wl_data_source_offer(wm->selection, "text/plain;charset=utf-8");
+ wl_data_source_add_listener(wm->selection,
+ &data_source_listener, wm);
+ wl_data_device_set_selection(xwm->data_device, wm->selection,
+ display_get_serial(wm->display));
}
static void
@@ -226,16 +213,12 @@ xwm_get_selection_data(struct xwm_wm *wm)
dump_property(wm, wm->atom.wl_selection, reply);
wm->incr = 0;
wm->property_start = 0;
- wm->property_source =
- wl_event_loop_add_fd(wm->server->loop,
- wm->data_source_fd,
- WL_EVENT_WRITABLE,
- xwm_write_property,
- wm);
+ wm->selection_write_task.run = xwm_write_property;
+ display_watch_fd(wm->display, wm->data_source_fd,
+ EPOLLOUT, &wm->selection_write_task);
wm->property_reply = reply;
}
}
-
static void
xwm_handle_selection_notify(struct xwm_wm *wm, xcb_generic_event_t *event)
{
@@ -329,10 +312,11 @@ xwm_flush_source_data(struct xwm_wm *wm)
return length;
}
-static int
-xwm_read_data_source(int fd, uint32_t mask, void *data)
+static void
+xwm_read_data_source(struct task *task, uint32_t events)
{
- struct xwm_wm *wm = data;
+ struct xwm_wm *wm =
+ container_of(task, struct xwm_wm, selection_read_task);
int len, current, available;
void *p;
@@ -343,17 +327,17 @@ xwm_read_data_source(int fd, uint32_t mask, void *data)
p = (char *) wm->source_data.data + wm->source_data.size;
available = wm->source_data.alloc - current;
- len = read(fd, p, available);
+ len = read(wm->data_source_fd, p, available);
if (len == -1) {
fprintf(stderr, "read error from data source: %m\n");
xwm_send_selection_notify(wm, XCB_ATOM_NONE);
- wl_event_source_remove(wm->property_source);
- close(fd);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
+ close(wm->data_source_fd);
wl_array_release(&wm->source_data);
}
- fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
- len, available, mask, len, (char *) p);
+ fprintf(stderr, "read %d (available %d) bytes: \"%.*s\"\n",
+ len, available, len, (char *) p);
wm->source_data.size = current + len;
if (wm->source_data.size >= incr_chunk_size) {
@@ -370,14 +354,14 @@ xwm_read_data_source(int fd, uint32_t mask, void *data)
1, &incr_chunk_size);
wm->selection_property_set = 1;
wm->flush_property_on_delete = 1;
- wl_event_source_remove(wm->property_source);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
xwm_send_selection_notify(wm, wm->selection_request.property);
} else if (wm->selection_property_set) {
fprintf(stderr, "got %zu bytes, waiting for "
"property delete\n", wm->source_data.size);
wm->flush_property_on_delete = 1;
- wl_event_source_remove(wm->property_source);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
} else {
fprintf(stderr, "got %zu bytes, "
"property deleted, seting new property\n",
@@ -390,8 +374,8 @@ xwm_read_data_source(int fd, uint32_t mask, void *data)
xwm_flush_source_data(wm);
xwm_send_selection_notify(wm, wm->selection_request.property);
xcb_flush(wm->conn);
- wl_event_source_remove(wm->property_source);
- close(fd);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
+ close(wm->data_source_fd);
wl_array_release(&wm->source_data);
wm->selection_request.requestor = XCB_NONE;
} else if (len == 0 && wm->incr) {
@@ -408,41 +392,35 @@ xwm_read_data_source(int fd, uint32_t mask, void *data)
xwm_flush_source_data(wm);
}
xcb_flush(wm->conn);
- wl_event_source_remove(wm->property_source);
+ display_unwatch_fd(wm->display, wm->data_source_fd);
close(wm->data_source_fd);
wm->data_source_fd = -1;
- close(fd);
} else {
fprintf(stderr, "nothing happened, buffered the bytes\n");
}
-
- return 1;
}
static void
xwm_send_data(struct xwm_wm *wm, xcb_atom_t target, const char *mime_type)
{
- struct wl_data_source *source;
- struct weston_seat *seat = xwm_pick_seat(wm);
int p[2];
- if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
+ if (pipe2(p, O_CLOEXEC) == -1) {
fprintf(stderr, "pipe2 failed: %m\n");
xwm_send_selection_notify(wm, XCB_ATOM_NONE);
return;
}
+ wm_send_selection(wm->xwm->wm, mime_type, p[1]);
+ close(p[1]);
+
wl_array_init(&wm->source_data);
wm->selection_target = target;
wm->data_source_fd = p[0];
- wm->property_source = wl_event_loop_add_fd(wm->server->loop,
- wm->data_source_fd,
- WL_EVENT_READABLE,
- xwm_read_data_source,
- wm);
-
- source = seat->seat.selection_data_source;
- source->send(source, mime_type, p[1]);
+ wm->selection_read_task.run = xwm_read_data_source;
+ display_watch_fd(wm->display, wm->data_source_fd,
+ EPOLLIN, &wm->selection_read_task);
+
}
static void
@@ -460,12 +438,9 @@ xwm_send_incr_chunk(struct xwm_wm *wm)
length = xwm_flush_source_data(wm);
if (wm->data_source_fd >= 0) {
- wm->property_source =
- wl_event_loop_add_fd(wm->server->loop,
- wm->data_source_fd,
- WL_EVENT_READABLE,
- xwm_read_data_source,
- wm);
+ wm->selection_read_task.run = xwm_read_data_source;
+ display_watch_fd(wm->display, wm->data_source_fd,
+ EPOLLIN, &wm->selection_read_task);
} else if (length > 0) {
/* Transfer is all done, but queue a flush for
* the delete of the last chunk so we can set
@@ -547,11 +522,10 @@ static void
xwm_handle_xfixes_selection_notify(struct xwm_wm *wm,
xcb_generic_event_t *event)
{
+ struct xwm *xwm = wm->xwm;
+
xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
(xcb_xfixes_selection_notify_event_t *) event;
- struct weston_compositor *compositor;
- struct weston_seat *seat = xwm_pick_seat(wm);
- uint32_t serial;
fprintf(stderr, "xfixes selection notify event: owner %d\n",
xfixes_selection_notify->owner);
@@ -560,9 +534,8 @@ xwm_handle_xfixes_selection_notify(struct xwm_wm *wm,
if (wm->selection_owner != wm->selection_window) {
/* A real X client selection went away, not our
* proxy selection. Clear the wayland selection. */
- compositor = wm->server->compositor;
- serial = wl_display_next_serial(compositor->wl_display);
- wl_seat_set_selection(&seat->seat, NULL, serial);
+ wl_data_device_set_selection(xwm->data_device,
+ NULL, display_get_serial(wm->display));
}
wm->selection_owner = XCB_WINDOW_NONE;
@@ -614,37 +587,17 @@ xwm_handle_selection_event(struct xwm_wm *wm, xcb_generic_event_t *event)
return 0;
}
-static void
-xwm_set_selection(struct wl_listener *listener, void *data)
+void
+xwm_set_selection(struct xwm *xwm, int has_text_plain)
{
- struct wl_seat *seat = data;
- struct xwm_wm *wm =
- container_of(listener, struct xwm_wm, selection_listener);
- struct wl_data_source *source = seat->selection_data_source;
- const char **p, **end;
- int has_text_plain = 0;
-
- if (source == NULL) {
- if (wm->selection_owner == wm->selection_window)
- xcb_set_selection_owner(wm->conn,
- XCB_ATOM_NONE,
- wm->atom.clipboard,
- wm->selection_timestamp);
- return;
- }
+ struct xwm_wm *wm = xwm->xwm_wm;
- if (source->send == data_source_send)
+ if (wm->selection_owner == wm->selection_window) {
+ xcb_set_selection_owner(wm->conn,
+ XCB_ATOM_NONE,
+ wm->atom.clipboard,
+ wm->selection_timestamp);
return;
-
- p = source->mime_types.data;
- end = (const char **)
- ((char *) source->mime_types.data + source->mime_types.size);
- while (p < end) {
- fprintf(stderr, " %s\n", *p);
- if (strcmp(*p, "text/plain") == 0 ||
- strcmp(*p, "text/plain;charset=utf-8") == 0)
- has_text_plain = 1;
- p++;
}
if (has_text_plain) {
@@ -663,7 +616,6 @@ xwm_set_selection(struct wl_listener *listener, void *data)
void
xwm_selection_init(struct xwm_wm *wm)
{
- struct weston_seat *seat;
uint32_t values[1], mask;
wm->selection_request.requestor = XCB_NONE;
@@ -693,9 +645,7 @@ xwm_selection_init(struct xwm_wm *wm)
xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
wm->atom.clipboard, mask);
- seat = xwm_pick_seat(wm);
- wm->selection_listener.notify = xwm_set_selection;
- wl_signal_add(&seat->seat.selection_signal, &wm->selection_listener);
-
- xwm_set_selection(&wm->selection_listener, seat);
+ xcb_set_selection_owner(wm->conn, XCB_ATOM_NONE,
+ wm->atom.clipboard, wm->selection_timestamp);
+ xcb_flush(wm->conn);
}
diff --git a/clients/xwm.c b/clients/xwm.c
index a6501e2..e175ffc 100644
--- a/clients/xwm.c
+++ b/clients/xwm.c
@@ -36,16 +36,6 @@
#include "../shared/cairo-util.h"
#include "../shared/xwayland-hash.h"
-struct xwm {
- struct wl_registry *registry;
- struct wl_display *wl_display;
- struct wl_compositor *compositor;
- struct wm *wm;
- struct display *display;
-
- struct xwm_wm *xwm_wm;
-};
-
struct motif_wm_hints {
uint32_t flags;
uint32_t functions;
@@ -589,6 +579,9 @@ get_window_state(void *data, struct wm *w, uint32_t id, enum wm_state state)
case WM_STATE_KILL:
set_state_kill(xwm, id);
break;
+ case WM_STATE_SELECTION:
+ xwm_set_selection(xwm, id);
+ break;
}
}
static int
@@ -1195,13 +1188,12 @@ xwm_handle_event(int fd, uint32_t mask, void *data)
int count = 0;
while (event = xcb_poll_for_event(wm->conn), event != NULL) {
-#if 0
if (xwm_handle_selection_event(wm, event)) {
free(event);
count++;
continue;
}
-#endif
+
switch (event->response_type & ~0x80) {
case XCB_BUTTON_PRESS:
case XCB_BUTTON_RELEASE:
@@ -1442,7 +1434,6 @@ wm_func(struct task *task, uint32_t events)
static void
xwm_create(struct xwm *xwm, int fd)
{
- struct display *display = xwm->display;
struct xwm_wm *wm;
xcb_screen_iterator_t s;
uint32_t values[1];
@@ -1453,6 +1444,7 @@ xwm_create(struct xwm *xwm, int fd)
return;
memset(wm, 0, sizeof *wm);
+ wm->display = xwm->display;
wm->window_hash = hash_table_create();
if (wm->window_hash == NULL) {
free(wm);
@@ -1470,7 +1462,7 @@ xwm_create(struct xwm *xwm, int fd)
}
wm->wm_task.run = wm_func;
- display_watch_fd(display, fd, EPOLLIN, &wm->wm_task);
+ display_watch_fd(wm->display, fd, EPOLLIN, &wm->wm_task);
s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
wm->screen = s.data;
@@ -1495,9 +1487,9 @@ xwm_create(struct xwm *xwm, int fd)
XCB_ATOM_ATOM,
32, /* format */
ARRAY_LENGTH(supported), supported);
-#if 0
+
xwm_selection_init(wm);
-#endif
+
xcb_flush(wm->conn);
xwm_create_cursors(wm);
@@ -1586,6 +1578,15 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
if (strcmp(interface, "wl_compositor") == 0) {
xwm->compositor = wl_registry_bind(registry, id,
&wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ xwm->seat = wl_registry_bind(registry, id,
+ &wl_seat_interface, 1);
+ xwm->data_device =
+ wl_data_device_manager_get_data_device(xwm->data_device_manager,
+ xwm->seat);
+ } else if (strcmp(interface, "wl_data_device_manager") == 0) {
+ xwm->data_device_manager = wl_registry_bind(registry, id,
+ &wl_data_device_manager_interface, 1);
} else if (!strcmp(interface, "wm")) {
xwm->wm = wl_registry_bind(registry, id,
&wm_interface, 1);
@@ -1629,6 +1630,8 @@ main(int argc, char **argv)
display_run(xwm.display);
xwm_destroy(xwm.xwm_wm);
+ wl_data_device_manager_destroy(xwm.data_device_manager);
+ wl_data_device_destroy(xwm.data_device);
display_destroy(xwm.display);
return 0;
diff --git a/clients/xwm.h b/clients/xwm.h
index aac124d..2c51d3a 100644
--- a/clients/xwm.h
+++ b/clients/xwm.h
@@ -26,10 +26,25 @@
#include "window.h"
+struct xwm {
+ struct wl_registry *registry;
+ struct wl_display *wl_display;
+ struct wl_compositor *compositor;
+ struct wl_seat *seat;
+ struct wl_data_device_manager *data_device_manager;
+ struct wl_data_device *data_device;
+
+ struct wm *wm;
+ struct display *display;
+
+ struct xwm_wm *xwm_wm;
+};
+
struct xwm_wm {
struct xwm *xwm;
struct task wm_task;
xcb_connection_t *conn;
+ struct display *display;
const xcb_query_extension_reply_t *xfixes;
xcb_screen_t *screen;
struct hash_table *window_hash;
@@ -40,13 +55,17 @@ struct xwm_wm {
int last_cursor;
xcb_render_pictforminfo_t format_rgb, format_rgba;
+ /* copy and paste proxy */
+ struct task selection_write_task;
+ struct task selection_read_task;
xcb_window_t selection_window;
xcb_window_t selection_owner;
int incr;
int data_source_fd;
- struct wl_event_source *property_source;
+ struct wl_data_offer *selection_offer;
xcb_get_property_reply_t *property_reply;
int property_start;
+ struct wl_data_source *selection;
struct wl_array source_data;
xcb_selection_request_event_t selection_request;
xcb_atom_t selection_target;
@@ -111,9 +130,8 @@ const char *
get_atom_name(xcb_connection_t *c, xcb_atom_t atom);
void
-xwm_wm_selection_init(struct xwm_wm *wm);
+xwm_selection_init(struct xwm_wm *wm);
int
-xwm_wm_handle_selection_event(struct xwm_wm *wm,
- xcb_generic_event_t *event);
-struct weston_seat *
-xwm_wm_pick_seat(struct xwm_wm *wm);
+xwm_handle_selection_event(struct xwm_wm *wm, xcb_generic_event_t *event);
+void
+xwm_set_selection(struct xwm *xwm, int has_text_plain);
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
index 86cf162..eef6874 100644
--- a/protocol/xserver.xml
+++ b/protocol/xserver.xml
@@ -123,6 +123,16 @@
<arg name="region" type="object" interface="wl_region" allow-null="true"/>
</request>
+ <request name="send_selection">
+ <description summary="send the selection data">
+ Request for data from another client. Send the data as the specified
+ mime-type over the passed fd.
+ </description>
+
+ <arg name="mime_type" type="string"/>
+ <arg name="fd" type="fd"/>
+ </request>
+
<request name="move">
<arg name="id" type="uint"/>
</request>
@@ -164,15 +174,17 @@
<entry name="deactivate" value="0" summary="deactivate all the windows"/>
<entry name="activate" value="1" summary="activate and give focus"/>
<entry name="kill" value="2" summary="send a kill signal"/>
+ <entry name="selection" value="3" summary="selection and its mime type"/>
</enum>
<event name="window_state">
<description summary="notifies window manager about window state">
- 'activate' and 'kill' require 'id' argument while 'deactivate' does
- not.
+ 'activate' and 'kill' require info argument while 'deactivate' does
+ not. 'selection' uses info for telling whether there is a plain text
+ on the selection.
</description>
- <arg name="id" type="uint"/>
+ <arg name="info" type="uint"/>
<arg name="state" type="uint"/>
</event>
</interface>
diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c
index a57e6ea..d595383 100644
--- a/src/xwayland/window-manager.c
+++ b/src/xwayland/window-manager.c
@@ -23,6 +23,8 @@
*/
#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
#include "xwayland.h"
#include "../../shared/xwayland-hash.h"
@@ -205,6 +207,25 @@ wm_get_input_region(struct wl_client *client, struct wl_resource *resource,
surface->geometry.dirty = 1;
}
+static struct weston_seat *
+weston_wm_pick_seat(struct weston_xserver *wxs)
+{
+ return container_of(wxs->compositor->seat_list.next,
+ struct weston_seat, link);
+}
+
+static void
+wm_handle_send_selection(struct wl_client *client,
+ struct wl_resource *resource, const char *mime_type, int32_t fd)
+{
+ struct weston_xserver *wxs = resource->data;
+ struct weston_seat *seat = weston_wm_pick_seat(wxs);
+ struct wl_data_source *source;
+
+ source = seat->seat.selection_data_source;
+ source->send(source, mime_type, fd);
+}
+
static void
weston_wm_activate_client(struct wl_listener *listener, void *data)
{
@@ -260,9 +281,43 @@ weston_wm_kill_client(struct wl_listener *listener, void *data)
}
static void
+weston_wm_set_selection(struct wl_listener *listener, void *data)
+{
+ struct weston_xserver *wxs = container_of(listener,
+ struct weston_xserver, selection_listener);
+ struct wl_seat *seat = data;
+ struct weston_surface *weston_surface =
+ (struct weston_surface *) seat->keyboard->focus;
+ struct xserver_window *window = get_xserver_window(weston_surface);
+ struct wl_data_source *source = seat->selection_data_source;
+ const char **p, **end;
+ int has_text_plain = 0;
+
+ /* just forward set_selection to WM when a Wayland client has
+ * initiated it */
+ if (window)
+ return;
+
+ p = source->mime_types.data;
+ end = (const char **)
+ ((char *) source->mime_types.data + source->mime_types.size);
+ while (p < end) {
+ weston_log(" %s\n", *p);
+ if (strcmp(*p, "text/plain") == 0 ||
+ strcmp(*p, "text/plain;charset=utf-8") == 0)
+ has_text_plain = 1;
+ p++;
+ }
+
+ wm_send_window_state(wxs->wm_resource,
+ has_text_plain, WM_STATE_SELECTION);
+}
+
+static void
wm_get_ready(struct wl_client *client, struct wl_resource *resource)
{
struct weston_xserver *wxs = resource->data;
+ struct weston_seat *seat = weston_wm_pick_seat(wxs);
/* sending now the X display connection together with the actual first
* X client that got connected */
@@ -284,6 +339,10 @@ wm_get_ready(struct wl_client *client, struct wl_resource *resource)
wxs->kill_listener.notify = weston_wm_kill_client;
wl_signal_add(&wxs->compositor->kill_signal,
&wxs->kill_listener);
+
+ wxs->selection_listener.notify = weston_wm_set_selection;
+ wl_signal_add(&seat->seat.selection_signal,
+ &wxs->selection_listener);
}
static void
@@ -294,13 +353,6 @@ wm_get_map(struct wl_client *client, struct wl_resource *resource, uint32_t id)
xserver_send_map(wxs->resource, id);
}
-static struct weston_seat *
-weston_wm_pick_seat(struct weston_xserver *wxs)
-{
- return container_of(wxs->compositor->seat_list.next,
- struct weston_seat, link);
-}
-
static void
wm_get_move(struct wl_client *client, struct wl_resource *resource,
uint32_t id)
@@ -349,6 +401,7 @@ const struct wm_interface wm_implementation = {
wm_get_window,
wm_get_opaque_override,
wm_get_input_region,
+ wm_handle_send_selection,
wm_get_move,
wm_get_resize
};
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index 1ddb51a..852fb5d 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -50,6 +50,7 @@ struct weston_xserver {
struct wl_listener activate_listener;
struct wl_listener position_listener;
struct wl_listener kill_listener;
+ struct wl_listener selection_listener;
};
extern const struct xserver_interface xserver_implementation;
--
1.7.9.5
More information about the wayland-devel
mailing list