blob: 579425b5d35888d3efc8c23801e56fc111b7deb7 [file] [log] [blame]
Kristian Høgsberg102bf032012-05-21 15:52:02 -04001/*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#define _GNU_SOURCE
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <unistd.h>
29#include <fcntl.h>
30
31#include "xwayland.h"
32
33static int
34weston_wm_write_property(int fd, uint32_t mask, void *data)
35{
36 struct weston_wm *wm = data;
37 unsigned char *property;
38 int len, remainder;
39
40 property = xcb_get_property_value(wm->property_reply);
41 remainder = xcb_get_property_value_length(wm->property_reply) -
42 wm->property_start;
43
44 len = write(fd, property + wm->property_start, remainder);
45 if (len == -1) {
46 free(wm->property_reply);
47 wl_event_source_remove(wm->property_source);
48 close(fd);
49 fprintf(stderr, "write error to target fd: %m\n");
50 return 1;
51 }
52
53 fprintf(stderr, "wrote %d (chunk size %d) of %d bytes\n",
54 wm->property_start + len,
55 len, xcb_get_property_value_length(wm->property_reply));
56
57 wm->property_start += len;
58 if (len == remainder) {
59 free(wm->property_reply);
60 wl_event_source_remove(wm->property_source);
61
62 if (wm->incr) {
63 xcb_delete_property(wm->conn,
64 wm->selection_window,
65 wm->atom.wl_selection);
66 } else {
67 fprintf(stderr, "transfer complete\n");
68 close(fd);
69 }
70 }
71
72 return 1;
73}
74
75static void
76weston_wm_get_incr_chunk(struct weston_wm *wm)
77{
78 xcb_get_property_cookie_t cookie;
79 xcb_get_property_reply_t *reply;
80
81 cookie = xcb_get_property(wm->conn,
82 0, /* delete */
83 wm->selection_window,
84 wm->atom.wl_selection,
85 XCB_GET_PROPERTY_TYPE_ANY,
86 0, /* offset */
87 0x1fffffff /* length */);
88
89 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
90
91 dump_property(wm, wm->atom.wl_selection, reply);
92
93 if (xcb_get_property_value_length(reply) > 0) {
94 wm->property_start = 0;
95 wm->property_source =
96 wl_event_loop_add_fd(wm->server->loop,
97 wm->data_source_fd,
98 WL_EVENT_WRITABLE,
99 weston_wm_write_property,
100 wm);
101 wm->property_reply = reply;
102 } else {
103 fprintf(stderr, "transfer complete\n");
104 close(wm->data_source_fd);
105 free(reply);
106 }
107}
108
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400109struct x11_data_source {
110 struct wl_data_source base;
111 struct weston_wm *wm;
112};
113
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400114static void
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400115data_source_accept(struct wl_data_source *source,
116 uint32_t time, const char *mime_type)
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400117{
118}
119
120static void
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400121data_source_send(struct wl_data_source *base,
122 const char *mime_type, int32_t fd)
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400123{
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400124 struct x11_data_source *source = (struct x11_data_source *) base;
125 struct weston_wm *wm = source->wm;
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400126
127 if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
128 /* Get data for the utf8_string target */
129 xcb_convert_selection(wm->conn,
130 wm->selection_window,
131 wm->atom.clipboard,
132 wm->atom.utf8_string,
133 wm->atom.wl_selection,
134 XCB_TIME_CURRENT_TIME);
135
136 xcb_flush(wm->conn);
137
138 fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400139 wm->data_source_fd = fcntl(fd, F_DUPFD_CLOEXEC, fd);
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400140 }
141}
142
143static void
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400144data_source_cancel(struct wl_data_source *source)
145{
146}
147
148static void
149weston_wm_get_selection_targets(struct weston_wm *wm)
150{
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400151 struct x11_data_source *source;
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400152 struct weston_compositor *compositor;
153 xcb_get_property_cookie_t cookie;
154 xcb_get_property_reply_t *reply;
155 xcb_atom_t *value;
156 char **p;
157 uint32_t i;
158
159 cookie = xcb_get_property(wm->conn,
160 1, /* delete */
161 wm->selection_window,
162 wm->atom.wl_selection,
163 XCB_GET_PROPERTY_TYPE_ANY,
164 0, /* offset */
165 4096 /* length */);
166
167 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
168
169 dump_property(wm, wm->atom.wl_selection, reply);
170
171 if (reply->type != XCB_ATOM_ATOM) {
172 free(reply);
173 return;
174 }
175
176 source = malloc(sizeof *source);
177 if (source == NULL)
178 return;
179
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400180 wl_signal_init(&source->base.resource.destroy_signal);
181 source->base.accept = data_source_accept;
182 source->base.send = data_source_send;
183 source->base.cancel = data_source_cancel;
184 source->base.resource.data = source;
185 source->wm = wm;
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400186
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400187 wl_array_init(&source->base.mime_types);
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400188 value = xcb_get_property_value(reply);
189 for (i = 0; i < reply->value_len; i++) {
190 if (value[i] == wm->atom.utf8_string) {
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400191 p = wl_array_add(&source->base.mime_types, sizeof *p);
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400192 if (p)
193 *p = strdup("text/plain;charset=utf-8");
194 }
195 }
196
197 compositor = wm->server->compositor;
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400198 wl_seat_set_selection(&compositor->seat->seat, &source->base,
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400199 wl_display_next_serial(compositor->wl_display));
200
201 free(reply);
202}
203
204static void
205weston_wm_get_selection_data(struct weston_wm *wm)
206{
207 xcb_get_property_cookie_t cookie;
208 xcb_get_property_reply_t *reply;
209
210 cookie = xcb_get_property(wm->conn,
211 1, /* delete */
212 wm->selection_window,
213 wm->atom.wl_selection,
214 XCB_GET_PROPERTY_TYPE_ANY,
215 0, /* offset */
216 0x1fffffff /* length */);
217
218 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
219
220 if (reply->type == wm->atom.incr) {
221 dump_property(wm, wm->atom.wl_selection, reply);
222 wm->incr = 1;
223 free(reply);
224 } else {
225 dump_property(wm, wm->atom.wl_selection, reply);
226 wm->incr = 0;
227 wm->property_start = 0;
228 wm->property_source =
229 wl_event_loop_add_fd(wm->server->loop,
230 wm->data_source_fd,
231 WL_EVENT_WRITABLE,
232 weston_wm_write_property,
233 wm);
234 wm->property_reply = reply;
235 }
236}
237
238static void
239weston_wm_handle_selection_notify(struct weston_wm *wm,
240 xcb_generic_event_t *event)
241{
242 xcb_selection_notify_event_t *selection_notify =
243 (xcb_selection_notify_event_t *) event;
244
245 if (selection_notify->property == XCB_ATOM_NONE) {
246 /* convert selection failed */
247 } else if (selection_notify->target == wm->atom.targets) {
248 weston_wm_get_selection_targets(wm);
249 } else {
250 weston_wm_get_selection_data(wm);
251 }
252}
253
254static const size_t incr_chunk_size = 64 * 1024;
255
256static void
257weston_wm_send_selection_notify(struct weston_wm *wm, xcb_atom_t property)
258{
259 xcb_selection_notify_event_t selection_notify;
260
261 memset(&selection_notify, 0, sizeof selection_notify);
262 selection_notify.response_type = XCB_SELECTION_NOTIFY;
263 selection_notify.sequence = 0;
264 selection_notify.time = wm->selection_request.time;
265 selection_notify.requestor = wm->selection_request.requestor;
266 selection_notify.selection = wm->selection_request.selection;
267 selection_notify.target = wm->selection_request.target;
268 selection_notify.property = property;
269
270 xcb_send_event(wm->conn, 0, /* propagate */
271 wm->selection_request.requestor,
272 XCB_EVENT_MASK_NO_EVENT, (char *) &selection_notify);
273}
274
275static void
276weston_wm_send_targets(struct weston_wm *wm)
277{
278 xcb_atom_t targets[] = {
279 wm->atom.timestamp,
280 wm->atom.targets,
281 wm->atom.utf8_string,
282 /* wm->atom.compound_text, */
283 wm->atom.text,
284 /* wm->atom.string */
285 };
286
287 xcb_change_property(wm->conn,
288 XCB_PROP_MODE_REPLACE,
289 wm->selection_request.requestor,
290 wm->selection_request.property,
291 XCB_ATOM_ATOM,
292 32, /* format */
293 ARRAY_LENGTH(targets), targets);
294
295 weston_wm_send_selection_notify(wm, wm->selection_request.property);
296}
297
298static void
299weston_wm_send_timestamp(struct weston_wm *wm)
300{
301 xcb_change_property(wm->conn,
302 XCB_PROP_MODE_REPLACE,
303 wm->selection_request.requestor,
304 wm->selection_request.property,
305 XCB_ATOM_INTEGER,
306 32, /* format */
307 1, &wm->selection_timestamp);
308
309 weston_wm_send_selection_notify(wm, wm->selection_request.property);
310}
311
312static int
313weston_wm_flush_source_data(struct weston_wm *wm)
314{
315 int length;
316
317 xcb_change_property(wm->conn,
318 XCB_PROP_MODE_REPLACE,
319 wm->selection_request.requestor,
320 wm->selection_request.property,
321 wm->selection_target,
322 8, /* format */
323 wm->source_data.size,
324 wm->source_data.data);
325 wm->selection_property_set = 1;
326 length = wm->source_data.size;
327 wm->source_data.size = 0;
328
329 return length;
330}
331
332static int
333weston_wm_read_data_source(int fd, uint32_t mask, void *data)
334{
335 struct weston_wm *wm = data;
336 int len, current, available;
337 void *p;
338
339 current = wm->source_data.size;
340 if (wm->source_data.size < incr_chunk_size)
341 p = wl_array_add(&wm->source_data, incr_chunk_size);
342 else
343 p = (char *) wm->source_data.data + wm->source_data.size;
344 available = wm->source_data.alloc - current;
345
346 len = read(fd, p, available);
347 if (len == -1) {
348 fprintf(stderr, "read error from data source: %m\n");
349 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
350 wl_event_source_remove(wm->property_source);
351 close(fd);
352 wl_array_release(&wm->source_data);
353 }
354
355 fprintf(stderr, "read %d (available %d, mask 0x%x) bytes: \"%.*s\"\n",
356 len, available, mask, len, (char *) p);
357
358 wm->source_data.size = current + len;
359 if (wm->source_data.size >= incr_chunk_size) {
360 if (!wm->incr) {
361 fprintf(stderr, "got %zu bytes, starting incr\n",
362 wm->source_data.size);
363 wm->incr = 1;
364 xcb_change_property(wm->conn,
365 XCB_PROP_MODE_REPLACE,
366 wm->selection_request.requestor,
367 wm->selection_request.property,
368 wm->atom.incr,
369 32, /* format */
370 1, &incr_chunk_size);
371 wm->selection_property_set = 1;
372 wm->flush_property_on_delete = 1;
373 wl_event_source_remove(wm->property_source);
374 weston_wm_send_selection_notify(wm, wm->selection_request.property);
375 } else if (wm->selection_property_set) {
376 fprintf(stderr, "got %zu bytes, waiting for "
377 "property delete\n", wm->source_data.size);
378
379 wm->flush_property_on_delete = 1;
380 wl_event_source_remove(wm->property_source);
381 } else {
382 fprintf(stderr, "got %zu bytes, "
383 "property deleted, seting new property\n",
384 wm->source_data.size);
385 weston_wm_flush_source_data(wm);
386 }
387 } else if (len == 0 && !wm->incr) {
388 fprintf(stderr, "non-incr transfer complete\n");
389 /* Non-incr transfer all done. */
390 weston_wm_flush_source_data(wm);
391 weston_wm_send_selection_notify(wm, wm->selection_request.property);
392 xcb_flush(wm->conn);
393 wl_event_source_remove(wm->property_source);
394 close(fd);
395 wl_array_release(&wm->source_data);
396 wm->selection_request.requestor = XCB_NONE;
397 } else if (len == 0 && wm->incr) {
398 fprintf(stderr, "incr transfer complete\n");
399
400 wm->flush_property_on_delete = 1;
401 if (wm->selection_property_set) {
402 fprintf(stderr, "got %zu bytes, waiting for "
403 "property delete\n", wm->source_data.size);
404 } else {
405 fprintf(stderr, "got %zu bytes, "
406 "property deleted, seting new property\n",
407 wm->source_data.size);
408 weston_wm_flush_source_data(wm);
409 }
410 xcb_flush(wm->conn);
411 wl_event_source_remove(wm->property_source);
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400412 close(wm->data_source_fd);
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400413 wm->data_source_fd = -1;
414 close(fd);
415 } else {
416 fprintf(stderr, "nothing happened, buffered the bytes\n");
417 }
418
419 return 1;
420}
421
422static void
423weston_wm_send_data(struct weston_wm *wm, xcb_atom_t target, const char *mime_type)
424{
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400425 struct wl_data_source *source;
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400426 struct wl_seat *seat = &wm->server->compositor->seat->seat;
427 int p[2];
428
429 if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1) {
430 fprintf(stderr, "pipe2 failed: %m\n");
431 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
432 return;
433 }
434
435 wl_array_init(&wm->source_data);
436 wm->selection_target = target;
437 wm->data_source_fd = p[0];
438 wm->property_source = wl_event_loop_add_fd(wm->server->loop,
439 wm->data_source_fd,
440 WL_EVENT_READABLE,
441 weston_wm_read_data_source,
442 wm);
443
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400444 source = seat->selection_data_source;
445 source->send(source, mime_type, p[1]);
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400446}
447
448static void
449weston_wm_send_incr_chunk(struct weston_wm *wm)
450{
451 int length;
452
453 fprintf(stderr, "property deleted\n");
454
455 wm->selection_property_set = 0;
456 if (wm->flush_property_on_delete) {
457 fprintf(stderr, "setting new property, %zu bytes\n",
458 wm->source_data.size);
459 wm->flush_property_on_delete = 0;
460 length = weston_wm_flush_source_data(wm);
461
462 if (wm->data_source_fd >= 0) {
463 wm->property_source =
464 wl_event_loop_add_fd(wm->server->loop,
465 wm->data_source_fd,
466 WL_EVENT_READABLE,
467 weston_wm_read_data_source,
468 wm);
469 } else if (length > 0) {
470 /* Transfer is all done, but queue a flush for
471 * the delete of the last chunk so we can set
472 * the 0 sized propert to signal the end of
473 * the transfer. */
474 wm->flush_property_on_delete = 1;
475 wl_array_release(&wm->source_data);
476 } else {
477 wm->selection_request.requestor = XCB_NONE;
478 }
479 }
480}
481
482static int
483weston_wm_handle_selection_property_notify(struct weston_wm *wm,
484 xcb_generic_event_t *event)
485{
486 xcb_property_notify_event_t *property_notify =
487 (xcb_property_notify_event_t *) event;
488
489 if (property_notify->window == wm->selection_window) {
490 if (property_notify->state == XCB_PROPERTY_NEW_VALUE &&
491 property_notify->atom == wm->atom.wl_selection &&
492 wm->incr)
493 weston_wm_get_incr_chunk(wm);
494 return 1;
495 } else if (property_notify->window == wm->selection_request.requestor) {
496 if (property_notify->state == XCB_PROPERTY_DELETE &&
497 property_notify->atom == wm->selection_request.property &&
498 wm->incr)
499 weston_wm_send_incr_chunk(wm);
500 return 1;
501 }
502
503 return 0;
504}
505
506static void
507weston_wm_handle_selection_request(struct weston_wm *wm,
508 xcb_generic_event_t *event)
509{
510 xcb_selection_request_event_t *selection_request =
511 (xcb_selection_request_event_t *) event;
512
513 fprintf(stderr, "selection request, %s, ",
514 get_atom_name(wm->conn, selection_request->selection));
515 fprintf(stderr, "target %s, ",
516 get_atom_name(wm->conn, selection_request->target));
517 fprintf(stderr, "property %s\n",
518 get_atom_name(wm->conn, selection_request->property));
519
520 wm->selection_request = *selection_request;
521 wm->incr = 0;
522 wm->flush_property_on_delete = 0;
523
Kristian Høgsbergcba022a2012-06-04 10:11:45 -0400524 if (selection_request->selection == wm->atom.clipboard_manager) {
525 /* The weston clipboard should already have grabbed
526 * the first target, so just send selection notify
527 * now. This isn't synchronized with the clipboard
528 * finishing getting the data, so there's a race here. */
529 weston_wm_send_selection_notify(wm, wm->selection_request.property);
530 return;
531 }
532
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400533 if (selection_request->target == wm->atom.targets) {
534 weston_wm_send_targets(wm);
535 } else if (selection_request->target == wm->atom.timestamp) {
536 weston_wm_send_timestamp(wm);
537 } else if (selection_request->target == wm->atom.utf8_string ||
538 selection_request->target == wm->atom.text) {
539 weston_wm_send_data(wm, wm->atom.utf8_string,
540 "text/plain;charset=utf-8");
541 } else {
542 fprintf(stderr, "can only handle UTF8_STRING targets...\n");
543 weston_wm_send_selection_notify(wm, XCB_ATOM_NONE);
544 }
545}
546
547static void
548weston_wm_handle_xfixes_selection_notify(struct weston_wm *wm,
549 xcb_generic_event_t *event)
550{
551 xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
552 (xcb_xfixes_selection_notify_event_t *) event;
Kristian Høgsberg80566732012-06-01 00:08:12 -0400553 struct weston_compositor *compositor;
554 uint32_t serial;
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400555
556 printf("xfixes selection notify event: owner %d\n",
557 xfixes_selection_notify->owner);
558
Kristian Høgsberg80566732012-06-01 00:08:12 -0400559 if (xfixes_selection_notify->owner == XCB_WINDOW_NONE) {
560 if (wm->selection_owner != wm->selection_window) {
561 /* A real X client selection went away, not our
562 * proxy selection. Clear the wayland selection. */
563 compositor = wm->server->compositor;
564 serial = wl_display_next_serial(compositor->wl_display);
565 wl_seat_set_selection(&compositor->seat->seat, NULL, serial);
566 }
567
568 wm->selection_owner = XCB_WINDOW_NONE;
569
570 return;
571 }
572
573 wm->selection_owner = xfixes_selection_notify->owner;
574
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400575 /* We have to use XCB_TIME_CURRENT_TIME when we claim the
576 * selection, so grab the actual timestamp here so we can
577 * answer TIMESTAMP conversion requests correctly. */
578 if (xfixes_selection_notify->owner == wm->selection_window) {
579 wm->selection_timestamp = xfixes_selection_notify->timestamp;
580 fprintf(stderr, "our window, skipping\n");
581 return;
582 }
583
584 wm->incr = 0;
585 xcb_convert_selection(wm->conn, wm->selection_window,
586 wm->atom.clipboard,
587 wm->atom.targets,
588 wm->atom.wl_selection,
589 xfixes_selection_notify->timestamp);
590
591 xcb_flush(wm->conn);
592}
593
594int
595weston_wm_handle_selection_event(struct weston_wm *wm,
596 xcb_generic_event_t *event)
597{
598 switch (event->response_type & ~0x80) {
599 case XCB_SELECTION_NOTIFY:
600 weston_wm_handle_selection_notify(wm, event);
601 return 1;
602 case XCB_PROPERTY_NOTIFY:
603 return weston_wm_handle_selection_property_notify(wm, event);
604 case XCB_SELECTION_REQUEST:
605 weston_wm_handle_selection_request(wm, event);
606 return 1;
607 }
608
609 switch (event->response_type - wm->xfixes->first_event) {
610 case XCB_XFIXES_SELECTION_NOTIFY:
611 weston_wm_handle_xfixes_selection_notify(wm, event);
612 return 1;
613 }
614
615 return 0;
616}
617
618void
619weston_wm_set_selection(struct wl_listener *listener, void *data)
620{
621 struct wl_seat *seat = data;
622 struct weston_wm *wm =
623 container_of(listener, struct weston_wm, selection_listener);
624 struct wl_data_source *source = seat->selection_data_source;
625 const char **p, **end;
626 int has_text_plain = 0;
627
Kristian Høgsberg80566732012-06-01 00:08:12 -0400628 if (source == NULL) {
629 if (wm->selection_owner == wm->selection_window)
630 xcb_set_selection_owner(wm->conn,
631 XCB_ATOM_NONE,
632 wm->atom.clipboard,
633 wm->selection_timestamp);
634 return;
635 }
636
Kristian Høgsbergc65d56a2012-06-02 21:23:01 -0400637 if (source->send == data_source_send)
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400638 return;
639
Kristian Høgsberg102bf032012-05-21 15:52:02 -0400640 p = source->mime_types.data;
641 end = (const char **)
642 ((char *) source->mime_types.data + source->mime_types.size);
643 while (p < end) {
644 fprintf(stderr, " %s\n", *p);
645 if (strcmp(*p, "text/plain") == 0 ||
646 strcmp(*p, "text/plain;charset=utf-8") == 0)
647 has_text_plain = 1;
648 p++;
649 }
650
651 if (has_text_plain) {
652 xcb_set_selection_owner(wm->conn,
653 wm->selection_window,
654 wm->atom.clipboard,
655 XCB_TIME_CURRENT_TIME);
656 } else {
657 xcb_set_selection_owner(wm->conn,
658 XCB_ATOM_NONE,
659 wm->atom.clipboard,
660 XCB_TIME_CURRENT_TIME);
661 }
662}
Kristian Høgsberg4dec0112012-06-03 09:18:06 -0400663
664void
665weston_wm_selection_init(struct weston_wm *wm)
666{
667 struct wl_seat *seat;
668 uint32_t values[1], mask;
669
670 wm->selection_request.requestor = XCB_NONE;
671
672 values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
673 wm->selection_window = xcb_generate_id(wm->conn);
674 xcb_create_window(wm->conn,
675 XCB_COPY_FROM_PARENT,
676 wm->selection_window,
677 wm->screen->root,
678 0, 0,
679 10, 10,
680 0,
681 XCB_WINDOW_CLASS_INPUT_OUTPUT,
682 wm->screen->root_visual,
683 XCB_CW_EVENT_MASK, values);
684
Kristian Høgsbergcba022a2012-06-04 10:11:45 -0400685 xcb_set_selection_owner(wm->conn,
686 wm->selection_window,
687 wm->atom.clipboard_manager,
688 XCB_TIME_CURRENT_TIME);
689
Kristian Høgsberg4dec0112012-06-03 09:18:06 -0400690 mask =
691 XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
692 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
693 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
694 xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
695 wm->atom.clipboard, mask);
696
697 seat = &wm->server->compositor->seat->seat;
698 wm->selection_listener.notify = weston_wm_set_selection;
699 wl_signal_add(&seat->selection_signal, &wm->selection_listener);
Kristian Høgsberge2203272012-06-03 10:32:48 -0400700
701 weston_wm_set_selection(&wm->selection_listener, seat);
Kristian Høgsberg4dec0112012-06-03 09:18:06 -0400702}