aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xwayland/selection.c90
-rw-r--r--xwayland/xwm.c1
-rw-r--r--xwayland/xwm.h4
3 files changed, 94 insertions, 1 deletions
diff --git a/xwayland/selection.c b/xwayland/selection.c
index 911a3627..acc93728 100644
--- a/xwayland/selection.c
+++ b/xwayland/selection.c
@@ -1,5 +1,6 @@
#define _XOPEN_SOURCE 700
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
#include <xcb/xfixes.h>
#include <fcntl.h>
@@ -35,8 +36,95 @@ static void xwm_handle_selection_request(struct wlr_xwm *xwm,
return;
}
+static int writable_callback(int fd, uint32_t mask, void *data) {
+ struct wlr_xwm *xwm = data;
+
+ unsigned char *property = xcb_get_property_value(xwm->property_reply);
+ int remainder = xcb_get_property_value_length(xwm->property_reply) -
+ xwm->property_start;
+
+ int len = write(fd, property + xwm->property_start, remainder);
+ if (len == -1) {
+ free(xwm->property_reply);
+ xwm->property_reply = NULL;
+ if (xwm->property_source) {
+ wl_event_source_remove(xwm->property_source);
+ }
+ xwm->property_source = NULL;
+ close(fd);
+ wlr_log(L_ERROR, "write error to target fd: %m\n");
+ return 1;
+ }
+
+ wlr_log(L_DEBUG, "wrote %d (chunk size %d) of %d bytes\n",
+ xwm->property_start + len,
+ len, xcb_get_property_value_length(xwm->property_reply));
+
+ xwm->property_start += len;
+ if (len == remainder) {
+ free(xwm->property_reply);
+ xwm->property_reply = NULL;
+ if (xwm->property_source) {
+ wl_event_source_remove(xwm->property_source);
+ }
+ xwm->property_source = NULL;
+
+ if (xwm->incr) {
+ xcb_delete_property(xwm->xcb_conn,
+ xwm->selection_window,
+ xwm->atoms[WL_SELECTION]);
+ } else {
+ wlr_log(L_DEBUG, "transfer complete\n");
+ close(fd);
+ }
+ }
+
+ return 1;
+}
+
+static void xwm_write_property(struct wlr_xwm *xwm,
+ xcb_get_property_reply_t *reply) {
+ xwm->property_start = 0;
+ xwm->property_reply = reply;
+ writable_callback(xwm->data_source_fd, WL_EVENT_WRITABLE, xwm);
+
+ if (xwm->property_reply) {
+ struct wl_event_loop *loop =
+ wl_display_get_event_loop(xwm->xwayland->wl_display);
+ xwm->property_source =
+ wl_event_loop_add_fd(loop,
+ xwm->data_source_fd,
+ WL_EVENT_WRITABLE,
+ writable_callback, xwm);
+ }
+}
+
static void xwm_get_selection_data(struct wlr_xwm *xwm) {
- wlr_log(L_DEBUG, "TODO: GET SELECTION DATA");
+ xcb_get_property_cookie_t cookie =
+ xcb_get_property(xwm->xcb_conn,
+ 1, // delete
+ xwm->selection_window,
+ xwm->atoms[WL_SELECTION],
+ XCB_GET_PROPERTY_TYPE_ANY,
+ 0, // offset
+ 0x1fffffff // length
+ );
+
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(xwm->xcb_conn, cookie, NULL);
+
+ if (reply == NULL) {
+ return;
+ } else if (reply->type == xwm->atoms[INCR]) {
+ xwm->incr = 1;
+ free(reply);
+ } else {
+ xwm->incr = 0;
+ // reply's ownership is transferred to wm, which is responsible
+ // for freeing it
+ xwm_write_property(xwm, reply);
+ }
+
}
struct x11_data_source {
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
index 5ce30f7b..af429a5c 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -47,6 +47,7 @@ const char *atom_map[ATOM_LAST] = {
"_WL_SELECTION",
"TARGETS",
"CLIPBOARD_MANAGER",
+ "INCR",
};
/* General helpers */
diff --git a/xwayland/xwm.h b/xwayland/xwm.h
index e1e42a54..a7bfd623 100644
--- a/xwayland/xwm.h
+++ b/xwayland/xwm.h
@@ -35,6 +35,7 @@ enum atom_name {
WL_SELECTION,
TARGETS,
CLIPBOARD_MANAGER,
+ INCR,
ATOM_LAST,
};
@@ -66,6 +67,9 @@ struct wlr_xwm {
xcb_timestamp_t selection_timestamp;
int incr;
int data_source_fd;
+ int property_start;
+ xcb_get_property_reply_t *property_reply;
+ struct wl_event_source *property_source;
struct wlr_xwayland_surface *focus_surface;