• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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