1 /*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34
35 #include <libweston/libweston.h>
36 #include "xwayland.h"
37 #include "shared/helpers.h"
38
39 #ifdef WM_DEBUG
40 #define wm_log(...) weston_log(__VA_ARGS__)
41 #else
42 #define wm_log(...) do {} while (0)
43 #endif
44
45 static int
writable_callback(int fd,uint32_t mask,void * data)46 writable_callback(int fd, uint32_t mask, void *data)
47 {
48 struct weston_wm *wm = data;
49 unsigned char *property;
50 int len, remainder;
51
52 property = xcb_get_property_value(wm->property_reply);
53 remainder = xcb_get_property_value_length(wm->property_reply) -
54 wm->property_start;
55
56 len = write(fd, property + wm->property_start, remainder);
57 if (len == -1) {
58 free(wm->property_reply);
59 wm->property_reply = NULL;
60 if (wm->property_source)
61 wl_event_source_remove(wm->property_source);
62 wm->property_source = NULL;
63 close(fd);
64 weston_log("write error to target fd: %s\n", strerror(errno));
65 return 1;
66 }
67
68 weston_log("wrote %d (chunk size %d) of %d bytes\n",
69 wm->property_start + len,
70 len, xcb_get_property_value_length(wm->property_reply));
71
72 wm->property_start += len;
73 if (len == remainder) {
74 free(wm->property_reply);
75 wm->property_reply = NULL;
76 if (wm->property_source)
77 wl_event_source_remove(wm->property_source);
78 wm->property_source = NULL;
79
80 if (wm->incr) {
81 xcb_delete_property(wm->conn,
82 wm->selection_window,
83 wm->atom.wl_selection);
84 } else {
85 weston_log("transfer complete\n");
86 close(fd);
87 }
88 }
89
90 return 1;
91 }
92
93 static void
weston_wm_write_property(struct weston_wm * wm,xcb_get_property_reply_t * reply)94 weston_wm_write_property(struct weston_wm *wm, xcb_get_property_reply_t *reply)
95 {
96 wm->property_start = 0;
97 wm->property_reply = reply;
98 writable_callback(wm->data_source_fd, WL_EVENT_WRITABLE, wm);
99
100 if (wm->property_reply)
101 wm->property_source =
102 wl_event_loop_add_fd(wm->server->loop,
103 wm->data_source_fd,
104 WL_EVENT_WRITABLE,
105 writable_callback, wm);
106 }
107
108 static void
weston_wm_get_incr_chunk(struct weston_wm * wm)109 weston_wm_get_incr_chunk(struct weston_wm *wm)
110 {
111 xcb_get_property_cookie_t cookie;
112 xcb_get_property_reply_t *reply;
113 FILE *fp;
114 char *logstr;
115 size_t logsize;
116
117 cookie = xcb_get_property(wm->conn,
118 0, /* delete */
119 wm->selection_window,
120 wm->atom.wl_selection,
121 XCB_GET_PROPERTY_TYPE_ANY,
122 0, /* offset */
123 0x1fffffff /* length */);
124
125 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
126 if (reply == NULL)
127 return;
128
129 fp = open_memstream(&logstr, &logsize);
130 if (fp) {
131 dump_property(fp, wm, wm->atom.wl_selection, reply);
132 if (fclose(fp) == 0)
133 wm_log("%s", logstr);
134 free(logstr);
135 }
136
137 if (xcb_get_property_value_length(reply) > 0) {
138 /* reply's ownership is transferred to wm, which is responsible
139 * for freeing it */
140 weston_wm_write_property(wm, reply);
141 } else {
142 weston_log("transfer complete\n");
143 close(wm->data_source_fd);
144 free(reply);
145 }
146 }
147
148 struct x11_data_source {
149 struct weston_data_source base;
150 struct weston_wm *wm;
151 };
152
153 static void
data_source_accept(struct weston_data_source * source,uint32_t time,const char * mime_type)154 data_source_accept(struct weston_data_source *source,
155 uint32_t time, const char *mime_type)
156 {
157 }
158
159 static void
data_source_send(struct weston_data_source * base,const char * mime_type,int32_t fd)160 data_source_send(struct weston_data_source *base,
161 const char *mime_type, int32_t fd)
162 {
163 struct x11_data_source *source = (struct x11_data_source *) base;
164 struct weston_wm *wm = source->wm;
165
166 if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
167 /* Get data for the utf8_string target */
168 xcb_convert_selection(wm->conn,
169 wm->selection_window,
170 wm->atom.clipboard,
171 wm->atom.utf8_string,
172 wm->atom.wl_selection,
173 XCB_TIME_CURRENT_TIME);
174
175 xcb_flush(wm->conn);
176
177 fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
178 wm->data_source_fd = fd;
179 }
180 }
181
182 static void
data_source_cancel(struct weston_data_source * source)183 data_source_cancel(struct weston_data_source *source)
184 {
185 }
186
187 static void
weston_wm_get_selection_targets(struct weston_wm * wm)188 weston_wm_get_selection_targets(struct weston_wm *wm)
189 {
190 struct x11_data_source *source;
191 struct weston_compositor *compositor;
192 struct weston_seat *seat = weston_wm_pick_seat(wm);
193 xcb_get_property_cookie_t cookie;
194 xcb_get_property_reply_t *reply;
195 xcb_atom_t *value;
196 char **p;
197 uint32_t i;
198 FILE *fp;
199 char *logstr;
200 size_t logsize;
201
202 cookie = xcb_get_property(wm->conn,
203 1, /* delete */
204 wm->selection_window,
205 wm->atom.wl_selection,
206 XCB_GET_PROPERTY_TYPE_ANY,
207 0, /* offset */
208 4096 /* length */);
209
210 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
211 if (reply == NULL)
212 return;
213
214 fp = open_memstream(&logstr, &logsize);
215 if (fp) {
216 dump_property(fp, wm, wm->atom.wl_selection, reply);
217 if (fclose(fp) == 0)
218 wm_log("%s", logstr);
219 free(logstr);
220 }
221
222 if (reply->type != XCB_ATOM_ATOM) {
223 free(reply);
224 return;
225 }
226
227 source = zalloc(sizeof *source);
228 if (source == NULL) {
229 free(reply);
230 return;
231 }
232
233 wl_signal_init(&source->base.destroy_signal);
234 source->base.accept = data_source_accept;
235 source->base.send = data_source_send;
236 source->base.cancel = data_source_cancel;
237 source->wm = wm;
238
239 wl_array_init(&source->base.mime_types);
240 value = xcb_get_property_value(reply);
241 for (i = 0; i < reply->value_len; i++) {
242 if (value[i] == wm->atom.utf8_string) {
243 p = wl_array_add(&source->base.mime_types, sizeof *p);
244 if (p)
245 *p = strdup("text/plain;charset=utf-8");
246 }
247 }
248
249 compositor = wm->server->compositor;
250 weston_seat_set_selection(seat, &source->base,
251 wl_display_next_serial(compositor->wl_display));
252
253 free(reply);
254 }
255
256 static void
weston_wm_get_selection_data(struct weston_wm * wm)257 weston_wm_get_selection_data(struct weston_wm *wm)
258 {
259 xcb_get_property_cookie_t cookie;
260 xcb_get_property_reply_t *reply;
261 FILE *fp;
262 char *logstr;
263 size_t logsize;
264
265 cookie = xcb_get_property(wm->conn,
266 1, /* delete */
267 wm->selection_window,
268 wm->atom.wl_selection,
269 XCB_GET_PROPERTY_TYPE_ANY,
270 0, /* offset */
271 0x1fffffff /* length */);
272
273 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
274
275 fp = open_memstream(&logstr, &logsize);
276 if (fp) {
277 dump_property(fp, wm, wm->atom.wl_selection, reply);
278 if (fclose(fp) == 0)
279 wm_log("%s", logstr);
280 free(logstr);
281 }
282
283 if (reply == NULL) {
284 return;
285 } else if (reply->type == wm->atom.incr) {
286 wm->incr = 1;
287 free(reply);
288 } else {
289 wm->incr = 0;
290 /* reply's ownership is transferred to wm, which is responsible
291 * for freeing it */
292 weston_wm_write_property(wm, reply);
293 }
294 }
295
296 static void
weston_wm_handle_selection_notify(struct weston_wm * wm,xcb_generic_event_t * event)297 weston_wm_handle_selection_notify(struct weston_wm *wm,
298 xcb_generic_event_t *event)
299 {
300 xcb_selection_notify_event_t *selection_notify =
301 (xcb_selection_notify_event_t *) event;
302
303 if (selection_notify->property == XCB_ATOM_NONE) {
304 /* convert selection failed */
305 } else if (selection_notify->target == wm->atom.targets) {
306 weston_wm_get_selection_targets(wm);
307 } else {
308 weston_wm_get_selection_data(wm);
309 }
310 }
311
312 static const size_t incr_chunk_size = 64 * 1024;
313
314 static void
weston_wm_send_selection_notify(struct weston_wm * wm,xcb_atom_t property)315 weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property)
316 {
317 xcb_selection_notify_event_t selection_notify;
318
319 memset(&selection_notify, 0, sizeof selection_notify);
320 selection_notify.response_type = XCB_SELECTION_NOTIFY;
321 selection_notify.sequence = 0;
322 selection_notify.time = wm->selection_request.time;
323 selection_notify.requestor = wm->selection_request.requestor;
324 selection_notify.selection = wm->selection_request.selection;
325 selection_notify.target = wm->selection_request.target;
326 selection_notify.property = property;
327
328 xcb_send_event(wm->conn, 0, /* propagate */
329 wm->selection_request.requestor,
330 XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify);
331 }
332
333 static void
weston_wm_send_targets(struct weston_wm * wm)334 weston_wm_send_targets(struct weston_wm *wm)
335 {
336 xcb_atom_t targets[] = {
337 wm->atom.timestamp,
338 wm->atom.targets,
339 wm->atom.utf8_string,
340 /* wm->atom.compound_text, */
341 wm->atom.text,
342 /* wm->atom.string */
343 };
344
345 xcb_change_property(wm->conn,
346 XCB_PROP_MODE_REPLACE,
347 wm->selection_request.requestor,
348 wm->selection_request.property,
349 XCB_ATOM_ATOM,
350 32, /* format */
351 ARRAY_LENGTH(targets), targets);
352
353 weston_wm_send_selection_notify(wm, wm->selection_request.property);
354 }
355
356 static void
weston_wm_send_timestamp(struct weston_wm * wm)357 weston_wm_send_timestamp(struct weston_wm *wm)
358 {
359 xcb_change_property(wm->conn,
360 XCB_PROP_MODE_REPLACE,
361 wm->selection_request.requestor,
362 wm->selection_request.property,
363 XCB_ATOM_INTEGER,
364 32, /* format */
365 1, &wm->selection_timestamp);
366
367 weston_wm_send_selection_notify(wm, wm->selection_request.property);
368 }
369
370 static int
weston_wm_flush_source_data(struct weston_wm * wm)371 weston_wm_flush_source_data(struct weston_wm *wm)
372 {
373 int length;
374
375 xcb_change_property(wm->conn,
376 XCB_PROP_MODE_REPLACE,
377 wm->selection_request.requestor,
378 wm->selection_request.property,
379 wm->selection_target,
380 8, /* format */
381 wm->source_data.size,
382 wm->source_data.data);
383 wm->selection_property_set = 1;
384 length = wm->source_data.size;
385 wm->source_data.size = 0;
386
387 return length;
388 }
389
390 static int
weston_wm_read_data_source(int fd,uint32_t mask,void * data)391 weston_wm_read_data_source(int fd, uint32_t mask, void *data)
392 {
393 struct weston_wm *wm = data;
394 int len, current, available;
395 void *p;
396
397 current = wm->source_data.size;
398 if (wm->source_data.size < incr_chunk_size)
399 p = wl_array_add(&wm->source_data, incr_chunk_size);
400 else
401 p = (char *) wm->source_data.data + wm->source_data.size;
402 available = wm->source_data.alloc - current;
403
404 len = read(fd, p, available);
405 if (len == -1) {
406 weston_log("read error from data source: %s\n",
407 strerror(errno));
408 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
409 if (wm->property_source)
410 wl_event_source_remove(wm->property_source);
411 wm->property_source = NULL;
412 close(fd);
413 wl_array_release(&wm->source_data);
414 return 1;
415 }
416
417 weston_log("read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
418 len, available, mask, len, (char *) p);
419
420 wm->source_data.size = current + len;
421 if (wm->source_data.size >= incr_chunk_size) {
422 if (!wm->incr) {
423 weston_log("got %zu bytes, starting incr\n",
424 wm->source_data.size);
425 wm->incr = 1;
426 xcb_change_property(wm->conn,
427 XCB_PROP_MODE_REPLACE,
428 wm->selection_request.requestor,
429 wm->selection_request.property,
430 wm->atom.incr,
431 32, /* format */
432 1, &incr_chunk_size);
433 wm->selection_property_set = 1;
434 wm->flush_property_on_delete = 1;
435 if (wm->property_source)
436 wl_event_source_remove(wm->property_source);
437 wm->property_source = NULL;
438 weston_wm_send_selection_notify(wm, wm->selection_request.property);
439 } else if (wm->selection_property_set) {
440 weston_log("got %zu bytes, waiting for "
441 "property delete\n", wm->source_data.size);
442
443 wm->flush_property_on_delete = 1;
444 if (wm->property_source)
445 wl_event_source_remove(wm->property_source);
446 wm->property_source = NULL;
447 } else {
448 weston_log("got %zu bytes, "
449 "property deleted, setting new property\n",
450 wm->source_data.size);
451 weston_wm_flush_source_data(wm);
452 }
453 } else if (len == 0 && !wm->incr) {
454 weston_log("non-incr transfer complete\n");
455 /* Non-incr transfer all done. */
456 weston_wm_flush_source_data(wm);
457 weston_wm_send_selection_notify(wm, wm->selection_request.property);
458 xcb_flush(wm->conn);
459 if (wm->property_source)
460 wl_event_source_remove(wm->property_source);
461 wm->property_source = NULL;
462 close(fd);
463 wl_array_release(&wm->source_data);
464 wm->selection_request.requestor = XCB_NONE;
465 } else if (len == 0 && wm->incr) {
466 weston_log("incr transfer complete\n");
467
468 wm->flush_property_on_delete = 1;
469 if (wm->selection_property_set) {
470 weston_log("got %zu bytes, waiting for "
471 "property delete\n", wm->source_data.size);
472 } else {
473 weston_log("got %zu bytes, "
474 "property deleted, setting new property\n",
475 wm->source_data.size);
476 weston_wm_flush_source_data(wm);
477 }
478 xcb_flush(wm->conn);
479 if (wm->property_source)
480 wl_event_source_remove(wm->property_source);
481 wm->property_source = NULL;
482 close(wm->data_source_fd);
483 wm->data_source_fd = -1;
484 close(fd);
485 } else {
486 weston_log("nothing happened, buffered the bytes\n");
487 }
488
489 return 1;
490 }
491
492 static void
weston_wm_send_data(struct weston_wm * wm,xcb_atom_t target,const char * mime_type)493 weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type)
494 {
495 struct weston_data_source *source;
496 struct weston_seat *seat = weston_wm_pick_seat(wm);
497 int p[2];
498
499 if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
500 weston_log("pipe2 failed: %s\n", strerror(errno));
501 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
502 return;
503 }
504
505 wl_array_init(&wm->source_data);
506 wm->selection_target = target;
507 wm->data_source_fd = p[0];
508 wm->property_source = wl_event_loop_add_fd(wm->server->loop,
509 wm->data_source_fd,
510 WL_EVENT_READABLE,
511 weston_wm_read_data_source,
512 wm);
513
514 source = seat->selection_data_source;
515 source->send(source, mime_type, p[1]);
516 close(p[1]);
517 }
518
519 static void
weston_wm_send_incr_chunk(struct weston_wm * wm)520 weston_wm_send_incr_chunk(struct weston_wm *wm)
521 {
522 int length;
523
524 weston_log("property deleted\n");
525
526 wm->selection_property_set = 0;
527 if (wm->flush_property_on_delete) {
528 weston_log("setting new property, %zu bytes\n",
529 wm->source_data.size);
530 wm->flush_property_on_delete = 0;
531 length = weston_wm_flush_source_data(wm);
532
533 if (wm->data_source_fd >= 0) {
534 wm->property_source =
535 wl_event_loop_add_fd(wm->server->loop,
536 wm->data_source_fd,
537 WL_EVENT_READABLE,
538 weston_wm_read_data_source,
539 wm);
540 } else if (length > 0) {
541 /* Transfer is all done, but queue a flush for
542 * the delete of the last chunk so we can set
543 * the 0 sized property to signal the end of
544 * the transfer. */
545 wm->flush_property_on_delete = 1;
546 wl_array_release(&wm->source_data);
547 } else {
548 wm->selection_request.requestor = XCB_NONE;
549 }
550 }
551 }
552
553 static int
weston_wm_handle_selection_property_notify(struct weston_wm * wm,xcb_generic_event_t * event)554 weston_wm_handle_selection_property_notify(struct weston_wm *wm,
555 xcb_generic_event_t *event)
556 {
557 xcb_property_notify_event_t *property_notify =
558 (xcb_property_notify_event_t *) event;
559
560 if (property_notify->window == wm->selection_window) {
561 if (property_notify->state == XCB_PROPERTY_NEW_VALUE &&
562 property_notify->atom == wm->atom.wl_selection &&
563 wm->incr)
564 weston_wm_get_incr_chunk(wm);
565 return 1;
566 } else if (property_notify->window == wm->selection_request.requestor) {
567 if (property_notify->state == XCB_PROPERTY_DELETE &&
568 property_notify->atom == wm->selection_request.property &&
569 wm->incr)
570 weston_wm_send_incr_chunk(wm);
571 return 1;
572 }
573
574 return 0;
575 }
576
577 static void
weston_wm_handle_selection_request(struct weston_wm * wm,xcb_generic_event_t * event)578 weston_wm_handle_selection_request(struct weston_wm *wm,
579 xcb_generic_event_t *event)
580 {
581 xcb_selection_request_event_t *selection_request =
582 (xcb_selection_request_event_t *) event;
583
584 weston_log("selection request, %s, ",
585 get_atom_name(wm->conn, selection_request->selection));
586 weston_log_continue("target %s, ",
587 get_atom_name(wm->conn, selection_request->target));
588 weston_log_continue("property %s\n",
589 get_atom_name(wm->conn, selection_request->property));
590
591 wm->selection_request = *selection_request;
592 wm->incr = 0;
593 wm->flush_property_on_delete = 0;
594
595 if (selection_request->selection == wm->atom.clipboard_manager) {
596 /* The weston clipboard should already have grabbed
597 * the first target, so just send selection notify
598 * now. This isn't synchronized with the clipboard
599 * finishing getting the data, so there's a race here. */
600 weston_wm_send_selection_notify(wm, wm->selection_request.property);
601 return;
602 }
603
604 if (selection_request->target == wm->atom.targets) {
605 weston_wm_send_targets(wm);
606 } else if (selection_request->target == wm->atom.timestamp) {
607 weston_wm_send_timestamp(wm);
608 } else if (selection_request->target == wm->atom.utf8_string ||
609 selection_request->target == wm->atom.text) {
610 weston_wm_send_data(wm, wm->atom.utf8_string,
611 "text/plain;charset=utf-8");
612 } else {
613 weston_log("can only handle UTF8_STRING targets...\n");
614 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
615 }
616 }
617
618 static int
weston_wm_handle_xfixes_selection_notify(struct weston_wm * wm,xcb_generic_event_t * event)619 weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm,
620 xcb_generic_event_t *event)
621 {
622 xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
623 (xcb_xfixes_selection_notify_event_t *) event;
624 struct weston_compositor *compositor;
625 struct weston_seat *seat = weston_wm_pick_seat(wm);
626 uint32_t serial;
627
628 if (xfixes_selection_notify->selection != wm->atom.clipboard)
629 return 0;
630
631 weston_log("xfixes selection notify event: owner %d\n",
632 xfixes_selection_notify->owner);
633
634 if (xfixes_selection_notify->owner == XCB_WINDOW_NONE) {
635 if (wm->selection_owner != wm->selection_window) {
636 /* A real X client selection went away, not our
637 * proxy selection. Clear the wayland selection. */
638 compositor = wm->server->compositor;
639 serial = wl_display_next_serial(compositor->wl_display);
640 weston_seat_set_selection(seat, NULL, serial);
641 }
642
643 wm->selection_owner = XCB_WINDOW_NONE;
644
645 return 1;
646 }
647
648 wm->selection_owner = xfixes_selection_notify->owner;
649
650 /* We have to use XCB_TIME_CURRENT_TIME when we claim the
651 * selection, so grab the actual timestamp here so we can
652 * answer TIMESTAMP conversion requests correctly. */
653 if (xfixes_selection_notify->owner == wm->selection_window) {
654 wm->selection_timestamp = xfixes_selection_notify->timestamp;
655 weston_log("our window, skipping\n");
656 return 1;
657 }
658
659 wm->incr = 0;
660 xcb_convert_selection(wm->conn, wm->selection_window,
661 wm->atom.clipboard,
662 wm->atom.targets,
663 wm->atom.wl_selection,
664 xfixes_selection_notify->timestamp);
665
666 xcb_flush(wm->conn);
667
668 return 1;
669 }
670
671 int
weston_wm_handle_selection_event(struct weston_wm * wm,xcb_generic_event_t * event)672 weston_wm_handle_selection_event(struct weston_wm *wm,
673 xcb_generic_event_t *event)
674 {
675 switch (event->response_type & ~0x80) {
676 case XCB_SELECTION_NOTIFY:
677 weston_wm_handle_selection_notify(wm, event);
678 return 1;
679 case XCB_PROPERTY_NOTIFY:
680 return weston_wm_handle_selection_property_notify(wm, event);
681 case XCB_SELECTION_REQUEST:
682 weston_wm_handle_selection_request(wm, event);
683 return 1;
684 }
685
686 switch (event->response_type - wm->xfixes->first_event) {
687 case XCB_XFIXES_SELECTION_NOTIFY:
688 return weston_wm_handle_xfixes_selection_notify(wm, event);
689 }
690
691 return 0;
692 }
693
694 static void
weston_wm_set_selection(struct wl_listener * listener,void * data)695 weston_wm_set_selection(struct wl_listener *listener, void *data)
696 {
697 struct weston_seat *seat = data;
698 struct weston_wm *wm =
699 container_of(listener, struct weston_wm, selection_listener);
700 struct weston_data_source *source = seat->selection_data_source;
701
702 if (source == NULL) {
703 if (wm->selection_owner == wm->selection_window)
704 xcb_set_selection_owner(wm->conn,
705 XCB_ATOM_NONE,
706 wm->atom.clipboard,
707 wm->selection_timestamp);
708 return;
709 }
710
711 if (source->send == data_source_send)
712 return;
713
714 xcb_set_selection_owner(wm->conn,
715 wm->selection_window,
716 wm->atom.clipboard,
717 XCB_TIME_CURRENT_TIME);
718 }
719
720 void
weston_wm_selection_init(struct weston_wm * wm)721 weston_wm_selection_init(struct weston_wm *wm)
722 {
723 struct weston_seat *seat;
724 uint32_t values[1], mask;
725
726 wl_list_init(&wm->selection_listener.link);
727
728 wm->selection_request.requestor = XCB_NONE;
729
730 values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
731 wm->selection_window = xcb_generate_id(wm->conn);
732 xcb_create_window(wm->conn,
733 XCB_COPY_FROM_PARENT,
734 wm->selection_window,
735 wm->screen->root,
736 0, 0,
737 10, 10,
738 0,
739 XCB_WINDOW_CLASS_INPUT_OUTPUT,
740 wm->screen->root_visual,
741 XCB_CW_EVENT_MASK, values);
742
743 xcb_set_selection_owner(wm->conn,
744 wm->selection_window,
745 wm->atom.clipboard_manager,
746 XCB_TIME_CURRENT_TIME);
747
748 mask =
749 XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
750 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
751 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
752 xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
753 wm->atom.clipboard, mask);
754
755 seat = weston_wm_pick_seat(wm);
756 if (seat == NULL)
757 return;
758 wm->selection_listener.notify = weston_wm_set_selection;
759 wl_signal_add(&seat->selection_signal, &wm->selection_listener);
760
761 weston_wm_set_selection(&wm->selection_listener, seat);
762 }
763