1/*
2 * Copyright © 2010 Intel Corporation
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include <fcntl.h>
21#include <unistd.h>
22
23#include <gio/gunixinputstream.h>
24#include <gio/gunixoutputstream.h>
25#include <glib-unix.h>
26
27#include "gdkwayland.h"
28#include "gdkprivate-wayland.h"
29#include "gdkdisplay-wayland.h"
30#include "gdkdndprivate.h"
31#include "gdkselection.h"
32#include "gdkproperty.h"
33#include "gdkprivate.h"
34
35#include <string.h>
36
37typedef struct _SelectionBuffer SelectionBuffer;
38typedef struct _StoredSelection StoredSelection;
39typedef struct _AsyncWriteData AsyncWriteData;
40typedef struct _DataOfferData DataOfferData;
41
42struct _SelectionBuffer
43{
44 GInputStream *stream;
45 GCancellable *cancellable;
46 GByteArray *data;
47 GList *requestors;
48 GdkAtom selection;
49 GdkAtom target;
50 gint ref_count;
51};
52
53struct _StoredSelection
54{
55 GdkWindow *source;
56 GCancellable *cancellable;
57 guchar *data;
58 gsize data_len;
59 GdkAtom type;
60 gint fd;
61};
62
63struct _DataSourceData
64{
65 GdkWindow *window;
66 GdkAtom selection;
67};
68
69struct _DataOfferData
70{
71 GDestroyNotify destroy_notify;
72 gpointer offer_data;
73 GList *targets; /* List of GdkAtom */
74};
75
76struct _AsyncWriteData
77{
78 GOutputStream *stream;
79 GdkWaylandSelection *selection;
80 gsize index;
81};
82
83enum {
84 ATOM_PRIMARY,
85 ATOM_CLIPBOARD,
86 ATOM_DND
87};
88
89static GdkAtom atoms[3] = { 0 };
90
91struct _GdkWaylandSelection
92{
93 /* Destination-side data */
94 DataOfferData *dnd_offer;
95 DataOfferData *clipboard_offer;
96 DataOfferData *primary_offer;
97 GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
98 GHashTable *selection_buffers; /* Hashtable of target_atom->SelectionBuffer */
99
100 /* Source-side data */
101 StoredSelection stored_selection;
102 GArray *source_targets;
103 GdkAtom requested_target;
104
105 struct gtk_primary_selection_source *primary_source;
106 GdkWindow *primary_owner;
107
108 struct wl_data_source *clipboard_source;
109 GdkWindow *clipboard_owner;
110
111 struct wl_data_source *dnd_source; /* Owned by the GdkDragContext */
112 GdkWindow *dnd_owner;
113};
114
115static void selection_buffer_read (SelectionBuffer *buffer);
116static void async_write_data_write (AsyncWriteData *write_data);
117
118static void
119selection_buffer_notify (SelectionBuffer *buffer)
120{
121 GdkEvent *event;
122 GList *l;
123
124 for (l = buffer->requestors; l; l = l->next)
125 {
126 event = gdk_event_new (GDK_SELECTION_NOTIFY);
127 event->selection.window = g_object_ref (l->data);
128 event->selection.send_event = FALSE;
129 event->selection.selection = buffer->selection;
130 event->selection.target = buffer->target;
131 event->selection.property = gdk_atom_intern_static_string ("GDK_SELECTION");
132 event->selection.time = GDK_CURRENT_TIME;
133 event->selection.requestor = g_object_ref (l->data);
134
135 gdk_event_put (event);
136 gdk_event_free (event);
137 }
138}
139
140static SelectionBuffer *
141selection_buffer_new (GInputStream *stream,
142 GdkAtom selection,
143 GdkAtom target)
144{
145 SelectionBuffer *buffer;
146
147 buffer = g_new0 (SelectionBuffer, 1);
148 buffer->stream = (stream) ? g_object_ref (stream) : NULL;
149 buffer->cancellable = g_cancellable_new ();
150 buffer->data = g_byte_array_new ();
151 buffer->selection = selection;
152 buffer->target = target;
153 buffer->ref_count = 1;
154
155 if (stream)
156 selection_buffer_read (buffer);
157
158 return buffer;
159}
160
161static SelectionBuffer *
162selection_buffer_ref (SelectionBuffer *buffer)
163{
164 buffer->ref_count++;
165 return buffer;
166}
167
168static void
169selection_buffer_unref (SelectionBuffer *buffer_data)
170{
171 buffer_data->ref_count--;
172
173 if (buffer_data->ref_count != 0)
174 return;
175
176 if (buffer_data->cancellable)
177 g_object_unref (buffer_data->cancellable);
178
179 if (buffer_data->stream)
180 g_object_unref (buffer_data->stream);
181
182 if (buffer_data->data)
183 g_byte_array_unref (buffer_data->data);
184
185 g_free (buffer_data);
186}
187
188static void
189selection_buffer_append_data (SelectionBuffer *buffer,
190 gconstpointer data,
191 gsize len)
192{
193 g_byte_array_append (buffer->data, data, len);
194}
195
196static void
197selection_buffer_cancel_and_unref (SelectionBuffer *buffer_data)
198{
199 if (buffer_data->cancellable)
200 g_cancellable_cancel (buffer_data->cancellable);
201
202 selection_buffer_unref (buffer_data);
203}
204
205static void
206selection_buffer_add_requestor (SelectionBuffer *buffer,
207 GdkWindow *requestor)
208{
209 if (!g_list_find (buffer->requestors, requestor))
210 buffer->requestors = g_list_prepend (buffer->requestors,
211 g_object_ref (requestor));
212}
213
214static gboolean
215selection_buffer_remove_requestor (SelectionBuffer *buffer,
216 GdkWindow *requestor)
217{
218 GList *link = g_list_find (buffer->requestors, requestor);
219
220 if (!link)
221 return FALSE;
222
223 g_object_unref (link->data);
224 buffer->requestors = g_list_delete_link (buffer->requestors, link);
225 return TRUE;
226}
227
228static inline glong
229get_buffer_size (void)
230{
231 return sysconf (_SC_PAGESIZE);
232}
233
234static void
235selection_buffer_read_cb (GObject *object,
236 GAsyncResult *result,
237 gpointer user_data)
238{
239 SelectionBuffer *buffer = user_data;
240 gboolean finished = TRUE;
241 GError *error = NULL;
242 GBytes *bytes;
243
244 bytes = g_input_stream_read_bytes_finish (buffer->stream, result, &error);
245
246 if (bytes)
247 {
248 finished = g_bytes_get_size (bytes) < get_buffer_size ();
249 selection_buffer_append_data (buffer,
250 g_bytes_get_data (bytes, NULL),
251 g_bytes_get_size (bytes));
252 g_bytes_unref (bytes);
253 }
254
255 if (!finished)
256 selection_buffer_read (buffer);
257 else
258 {
259 if (error)
260 {
261 g_warning (G_STRLOC ": error reading selection buffer: %s", error->message);
262 g_error_free (error);
263 }
264 else
265 selection_buffer_notify (buffer);
266
267 g_input_stream_close (buffer->stream, NULL, NULL);
268 g_clear_object (&buffer->stream);
269 g_clear_object (&buffer->cancellable);
270 }
271
272 selection_buffer_unref (buffer);
273}
274
275static void
276selection_buffer_read (SelectionBuffer *buffer)
277{
278 selection_buffer_ref (buffer);
279 g_input_stream_read_bytes_async (buffer->stream, get_buffer_size(),
280 G_PRIORITY_DEFAULT,
281 buffer->cancellable, selection_buffer_read_cb,
282 buffer);
283}
284
285static DataOfferData *
286data_offer_data_new (gpointer offer,
287 GDestroyNotify destroy_notify)
288{
289 DataOfferData *info;
290
291 info = g_slice_new0 (DataOfferData);
292 info->offer_data = offer;
293 info->destroy_notify = destroy_notify;
294
295 return info;
296}
297
298static void
299data_offer_data_free (DataOfferData *info)
300{
301 info->destroy_notify (info->offer_data);
302 g_list_free (info->targets);
303 g_slice_free (DataOfferData, info);
304}
305
306GdkWaylandSelection *
307gdk_wayland_selection_new (void)
308{
309 GdkWaylandSelection *selection;
310
311 /* init atoms */
312 atoms[ATOM_PRIMARY] = gdk_atom_intern_static_string ("PRIMARY");
313 atoms[ATOM_CLIPBOARD] = gdk_atom_intern_static_string ("CLIPBOARD");
314 atoms[ATOM_DND] = gdk_atom_intern_static_string ("GdkWaylandSelection");
315
316 selection = g_new0 (GdkWaylandSelection, 1);
317 selection->selection_buffers =
318 g_hash_table_new_full (NULL, NULL, NULL,
319 (GDestroyNotify) selection_buffer_cancel_and_unref);
320 selection->offers =
321 g_hash_table_new_full (NULL, NULL, NULL,
322 (GDestroyNotify) data_offer_data_free);
323 selection->stored_selection.fd = -1;
324 selection->source_targets = g_array_new (FALSE, FALSE, sizeof (GdkAtom));
325 return selection;
326}
327
328void
329gdk_wayland_selection_free (GdkWaylandSelection *selection)
330{
331 g_hash_table_destroy (selection->selection_buffers);
332 g_array_unref (selection->source_targets);
333
334 g_hash_table_destroy (selection->offers);
335 g_free (selection->stored_selection.data);
336
337 if (selection->stored_selection.cancellable)
338 {
339 g_cancellable_cancel (selection->stored_selection.cancellable);
340 g_object_unref (selection->stored_selection.cancellable);
341 }
342
343 if (selection->stored_selection.fd > 0)
344 close (selection->stored_selection.fd);
345
346 if (selection->primary_source)
347 gtk_primary_selection_source_destroy (selection->primary_source);
348 if (selection->clipboard_source)
349 wl_data_source_destroy (selection->clipboard_source);
350 if (selection->dnd_source)
351 wl_data_source_destroy (selection->dnd_source);
352
353 g_free (selection);
354}
355
356static void
357data_offer_offer (void *data,
358 struct wl_data_offer *wl_data_offer,
359 const char *type)
360{
361 GdkWaylandSelection *selection = data;
362 DataOfferData *info;
363 GdkAtom atom = gdk_atom_intern (type, FALSE);
364
365 info = g_hash_table_lookup (selection->offers, wl_data_offer);
366
367 if (!info || g_list_find (info->targets, atom))
368 return;
369
370 info->targets = g_list_prepend (info->targets, atom);
371}
372
373static inline GdkDragAction
374_wl_to_gdk_actions (uint32_t dnd_actions)
375{
376 GdkDragAction actions = 0;
377
378 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
379 actions |= GDK_ACTION_COPY;
380 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
381 actions |= GDK_ACTION_MOVE;
382 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
383 actions |= GDK_ACTION_ASK;
384
385 return actions;
386}
387
388static void
389data_offer_source_actions (void *data,
390 struct wl_data_offer *wl_data_offer,
391 uint32_t source_actions)
392{
393 GdkDragContext *drop_context;
394 GdkDisplay *display;
395 GdkDevice *device;
396 GdkSeat *seat;
397
398 display = gdk_display_get_default ();
399 seat = gdk_display_get_default_seat (display);
400 device = gdk_seat_get_pointer (seat);
401 drop_context = gdk_wayland_device_get_drop_context (device);
402
403 drop_context->actions = _wl_to_gdk_actions (source_actions);
404
405 if (gdk_drag_context_get_dest_window (drop_context))
406 _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
407 GDK_CURRENT_TIME);
408}
409
410static void
411data_offer_action (void *data,
412 struct wl_data_offer *wl_data_offer,
413 uint32_t action)
414{
415 GdkDragContext *drop_context;
416 GdkDisplay *display;
417 GdkDevice *device;
418 GdkSeat *seat;
419
420 display = gdk_display_get_default ();
421 seat = gdk_display_get_default_seat (display);
422 device = gdk_seat_get_pointer (seat);
423 drop_context = gdk_wayland_device_get_drop_context (device);
424
425 drop_context->action = _wl_to_gdk_actions (action);
426
427 if (gdk_drag_context_get_dest_window (drop_context))
428 _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
429 GDK_CURRENT_TIME);
430}
431
432static const struct wl_data_offer_listener data_offer_listener = {
433 data_offer_offer,
434 data_offer_source_actions,
435 data_offer_action
436};
437
438static void
439primary_offer_offer (void *data,
440 struct gtk_primary_selection_offer *gtk_offer,
441 const char *type)
442{
443 GdkWaylandSelection *selection = data;
444 DataOfferData *info;
445 GdkAtom atom = gdk_atom_intern (type, FALSE);
446
447 info = g_hash_table_lookup (selection->offers, gtk_offer);
448
449 if (!info || g_list_find (info->targets, atom))
450 return;
451
452 info->targets = g_list_prepend (info->targets, atom);
453}
454
455static const struct gtk_primary_selection_offer_listener primary_offer_listener = {
456 primary_offer_offer,
457};
458
459DataOfferData *
460selection_lookup_offer_by_atom (GdkWaylandSelection *selection,
461 GdkAtom selection_atom)
462{
463 if (selection_atom == atoms[ATOM_PRIMARY])
464 return selection->primary_offer;
465 else if (selection_atom == atoms[ATOM_CLIPBOARD])
466 return selection->clipboard_offer;
467 else if (selection_atom == atoms[ATOM_DND])
468 return selection->dnd_offer;
469 else
470 return NULL;
471}
472
473void
474gdk_wayland_selection_ensure_offer (GdkDisplay *display,
475 struct wl_data_offer *wl_offer)
476{
477 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
478 DataOfferData *info;
479
480 info = g_hash_table_lookup (selection->offers, wl_offer);
481
482 if (!info)
483 {
484 info = data_offer_data_new (wl_offer,
485 (GDestroyNotify) wl_data_offer_destroy);
486 g_hash_table_insert (selection->offers, wl_offer, info);
487 wl_data_offer_add_listener (wl_offer,
488 &data_offer_listener,
489 selection);
490 }
491}
492
493void
494gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display,
495 struct gtk_primary_selection_offer *gtk_offer)
496{
497 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
498 DataOfferData *info;
499
500 info = g_hash_table_lookup (selection->offers, gtk_offer);
501
502 if (!info)
503 {
504 info = data_offer_data_new (gtk_offer,
505 (GDestroyNotify) gtk_primary_selection_offer_destroy);
506 g_hash_table_insert (selection->offers, gtk_offer, info);
507 gtk_primary_selection_offer_add_listener (gtk_offer,
508 &primary_offer_listener,
509 selection);
510 }
511}
512
513void
514gdk_wayland_selection_set_offer (GdkDisplay *display,
515 GdkAtom selection_atom,
516 gpointer wl_offer)
517{
518 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
519 struct wl_data_offer *prev_offer;
520 DataOfferData *info;
521
522 info = g_hash_table_lookup (selection->offers, wl_offer);
523
524 prev_offer = gdk_wayland_selection_get_offer (display, selection_atom);
525
526 if (prev_offer)
527 g_hash_table_remove (selection->offers, prev_offer);
528
529 if (selection_atom == atoms[ATOM_PRIMARY])
530 selection->primary_offer = info;
531 else if (selection_atom == atoms[ATOM_CLIPBOARD])
532 selection->clipboard_offer = info;
533 else if (selection_atom == atoms[ATOM_DND])
534 selection->dnd_offer = info;
535
536 /* Clear all buffers */
537 g_hash_table_remove_all (selection->selection_buffers);
538}
539
540gpointer
541gdk_wayland_selection_get_offer (GdkDisplay *display,
542 GdkAtom selection_atom)
543{
544 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
545 const DataOfferData *info;
546
547 info = selection_lookup_offer_by_atom (selection, selection_atom);
548
549 if (info)
550 return info->offer_data;
551
552 return NULL;
553}
554
555GList *
556gdk_wayland_selection_get_targets (GdkDisplay *display,
557 GdkAtom selection_atom)
558{
559 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
560 const DataOfferData *info;
561
562 info = selection_lookup_offer_by_atom (selection, selection_atom);
563
564 if (info)
565 return info->targets;
566
567 return NULL;
568}
569
570static void
571gdk_wayland_selection_emit_request (GdkWindow *window,
572 GdkAtom selection,
573 GdkAtom target)
574{
575 GdkEvent *event;
576
577 event = gdk_event_new (GDK_SELECTION_REQUEST);
578 event->selection.window = g_object_ref (window);
579 event->selection.send_event = FALSE;
580 event->selection.selection = selection;
581 event->selection.target = target;
582 event->selection.property = gdk_atom_intern_static_string ("GDK_SELECTION");
583 event->selection.time = GDK_CURRENT_TIME;
584 event->selection.requestor = g_object_ref (window);
585
586 gdk_event_put (event);
587 gdk_event_free (event);
588}
589
590static AsyncWriteData *
591async_write_data_new (GdkWaylandSelection *selection)
592{
593 AsyncWriteData *write_data;
594
595 write_data = g_slice_new0 (AsyncWriteData);
596 write_data->selection = selection;
597 write_data->stream =
598 g_unix_output_stream_new (selection->stored_selection.fd, TRUE);
599
600 selection->stored_selection.fd = -1;
601
602 return write_data;
603}
604
605static void
606async_write_data_free (AsyncWriteData *write_data)
607{
608 g_object_unref (write_data->stream);
609 g_slice_free (AsyncWriteData, write_data);
610}
611
612static void
613async_write_data_cb (GObject *object,
614 GAsyncResult *res,
615 gpointer user_data)
616{
617 AsyncWriteData *write_data = user_data;
618 GError *error = NULL;
619 gsize bytes_written;
620
621 bytes_written = g_output_stream_write_finish (G_OUTPUT_STREAM (object),
622 res, &error);
623 if (error)
624 {
625 if (error->domain != G_IO_ERROR ||
626 error->code != G_IO_ERROR_CANCELLED)
627 g_warning ("Error writing selection data: %s", error->message);
628
629 g_error_free (error);
630 async_write_data_free (write_data);
631 return;
632 }
633
634 write_data->index += bytes_written;
635
636 if (write_data->index <
637 write_data->selection->stored_selection.data_len)
638 {
639 /* Write the next chunk */
640 async_write_data_write (write_data);
641 }
642 else
643 async_write_data_free (write_data);
644}
645
646static void
647async_write_data_write (AsyncWriteData *write_data)
648{
649 GdkWaylandSelection *selection = write_data->selection;
650 gsize buf_len;
651 guchar *buf;
652
653 buf = selection->stored_selection.data;
654 buf_len = selection->stored_selection.data_len;
655
656 g_output_stream_write_async (write_data->stream,
657 &buf[write_data->index],
658 buf_len - write_data->index,
659 G_PRIORITY_DEFAULT,
660 selection->stored_selection.cancellable,
661 async_write_data_cb,
662 write_data);
663}
664
665static gboolean
666gdk_wayland_selection_check_write (GdkWaylandSelection *selection)
667{
668 AsyncWriteData *write_data;
669
670 if (selection->stored_selection.fd < 0)
671 return FALSE;
672
673 /* Cancel any previous ongoing async write */
674 if (selection->stored_selection.cancellable)
675 {
676 g_cancellable_cancel (selection->stored_selection.cancellable);
677 g_object_unref (selection->stored_selection.cancellable);
678 }
679
680 selection->stored_selection.cancellable = g_cancellable_new ();
681
682 write_data = async_write_data_new (selection);
683 async_write_data_write (write_data);
684 selection->stored_selection.fd = -1;
685
686 return TRUE;
687}
688
689void
690gdk_wayland_selection_store (GdkWindow *window,
691 GdkAtom type,
692 GdkPropMode mode,
693 const guchar *data,
694 gint len)
695{
696 GdkDisplay *display = gdk_window_get_display (window);
697 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
698 GArray *array;
699
700 if (type == gdk_atom_intern_static_string ("NULL"))
701 return;
702
703 array = g_array_new (TRUE, FALSE, sizeof (guchar));
704 g_array_append_vals (array, data, len);
705
706 if (selection->stored_selection.data)
707 {
708 if (mode != GDK_PROP_MODE_REPLACE &&
709 type != selection->stored_selection.type)
710 {
711 gchar *type_str, *stored_str;
712
713 type_str = gdk_atom_name (type);
714 stored_str = gdk_atom_name (selection->stored_selection.type);
715
716 g_warning (G_STRLOC ": Attempted to append/prepend selection data with "
717 "type %s into the current selection with type %s",
718 type_str, stored_str);
719 g_free (type_str);
720 g_free (stored_str);
721 return;
722 }
723
724 /* In these cases we also replace the stored data, so we
725 * apply the inverse operation into the just given data.
726 */
727 if (mode == GDK_PROP_MODE_APPEND)
728 g_array_prepend_vals (array, selection->stored_selection.data,
729 selection->stored_selection.data_len - 1);
730 else if (mode == GDK_PROP_MODE_PREPEND)
731 g_array_append_vals (array, selection->stored_selection.data,
732 selection->stored_selection.data_len - 1);
733
734 g_free (selection->stored_selection.data);
735 }
736
737 selection->stored_selection.source = window;
738 selection->stored_selection.data_len = array->len;
739 selection->stored_selection.data = (guchar *) g_array_free (array, FALSE);
740 selection->stored_selection.type = type;
741
742 gdk_wayland_selection_check_write (selection);
743}
744
745static SelectionBuffer *
746gdk_wayland_selection_lookup_requestor_buffer (GdkWindow *requestor)
747{
748 GdkDisplay *display = gdk_window_get_display (requestor);
749 GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
750 SelectionBuffer *buffer_data;
751 GHashTableIter iter;
752
753 g_hash_table_iter_init (&iter, selection->selection_buffers);
754
755 while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &buffer_data))
756 {
757 if (g_list_find (buffer_data->requestors, requestor))
758 return buffer_data;
759 }
760
761 return NULL;
762}
763
764static gboolean
765gdk_wayland_selection_source_handles_target (GdkWaylandSelection *wayland_selection,
766 GdkAtom target)
767{
768 GdkAtom atom;
769 guint i;
770
771 if (target == GDK_NONE)
772 return FALSE;
773
774 for (i = 0; i < wayland_selection->source_targets->len; i++)
775 {
776 atom = g_array_index (wayland_selection->source_targets, GdkAtom, i);
777
778 if (atom == target)
779 return TRUE;
780 }
781
782 return FALSE;
783}
784
785static gboolean
786gdk_wayland_selection_request_target (GdkWaylandSelection *wayland_selection,
787 GdkWindow *window,
788 GdkAtom selection,
789 GdkAtom target,
790 gint fd)
791{
792 if (wayland_selection->stored_selection.fd == fd &&
793 wayland_selection->requested_target == target)
794 return FALSE;
795
796 /* If we didn't issue gdk_wayland_selection_check_write() yet
797 * on a previous fd, it will still linger here. Just close it,
798 * as we can't have more than one fd on the fly.
799 */
800 if (wayland_selection->stored_selection.fd >= 0)
801 close (wayland_selection->stored_selection.fd);
802
803 wayland_selection->stored_selection.fd = fd;
804 wayland_selection->requested_target = target;
805
806 if (window &&
807 gdk_wayland_selection_source_handles_target (wayland_selection, target))
808 {
809 gdk_wayland_selection_emit_request (window, selection, target);
810 return TRUE;
811 }
812 else
813 {
814 close (fd);
815 wayland_selection->stored_selection.fd = -1;
816 }
817
818 return FALSE;
819}
820
821static void
822data_source_target (void *data,
823 struct wl_data_source *source,
824 const char *mime_type)
825{
826 g_debug (G_STRLOC ": %s source = %p, mime_type = %s",
827 G_STRFUNC, source, mime_type);
828}
829
830static void
831data_source_send (void *data,
832 struct wl_data_source *source,
833 const char *mime_type,
834 int32_t fd)
835{
836 GdkWaylandSelection *wayland_selection = data;
837 GdkWindow *window;
838 GdkAtom selection;
839
840 g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
841 G_STRFUNC, source, mime_type, fd);
842
843 if (!mime_type)
844 {
845 close (fd);
846 return;
847 }
848
849 if (source == wayland_selection->dnd_source)
850 {
851 window = wayland_selection->dnd_owner;
852 selection = atoms[ATOM_DND];
853 }
854 else if (source == wayland_selection->clipboard_source)
855 {
856 window = wayland_selection->clipboard_owner;
857 selection = atoms[ATOM_CLIPBOARD];
858 }
859 else
860 {
861 close (fd);
862 return;
863 }
864
865 if (!window)
866 return;
867
868 if (!gdk_wayland_selection_request_target (wayland_selection, window,
869 selection,
870 gdk_atom_intern (mime_type, FALSE),
871 fd))
872 gdk_wayland_selection_check_write (wayland_selection);
873}
874
875static void
876data_source_cancelled (void *data,
877 struct wl_data_source *source)
878{
879 GdkWaylandSelection *wayland_selection = data;
880 GdkDragContext *context;
881 GdkDisplay *display;
882 GdkAtom atom;
883
884 g_debug (G_STRLOC ": %s source = %p",
885 G_STRFUNC, source);
886
887 display = gdk_display_get_default ();
888
889 if (source == wayland_selection->dnd_source)
890 atom = atoms[ATOM_DND];
891 else if (source == wayland_selection->clipboard_source)
892 atom = atoms[ATOM_CLIPBOARD];
893 else
894 return;
895
896 context = gdk_wayland_drag_context_lookup_by_data_source (source);
897
898 if (context)
899 gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_ERROR);
900
901 gdk_selection_owner_set (NULL, atom, GDK_CURRENT_TIME, TRUE);
902 gdk_wayland_selection_unset_data_source (display, atom);
903}
904
905static void
906data_source_dnd_drop_performed (void *data,
907 struct wl_data_source *source)
908{
909 GdkDragContext *context;
910
911 context = gdk_wayland_drag_context_lookup_by_data_source (source);
912
913 if (!context)
914 return;
915
916 g_signal_emit_by_name (context, "drop-performed", GDK_CURRENT_TIME);
917}
918
919static void
920data_source_dnd_finished (void *data,
921 struct wl_data_source *source)
922{
923 GdkDisplay *display = gdk_display_get_default ();
924 GdkDragContext *context;
925
926 context = gdk_wayland_drag_context_lookup_by_data_source (source);
927
928 if (!context)
929 return;
930
931 if (context->action == GDK_ACTION_MOVE)
932 {
933 gdk_wayland_selection_emit_request (context->source_window,
934 atoms[ATOM_DND],
935 gdk_atom_intern_static_string ("DELETE"));
936 }
937
938 g_signal_emit_by_name (context, "dnd-finished");
939 gdk_selection_owner_set (NULL, atoms[ATOM_DND], GDK_CURRENT_TIME, TRUE);
940 gdk_wayland_selection_clear_targets (display, atoms[ATOM_DND]);
941}
942
943static void
944data_source_action (void *data,
945 struct wl_data_source *source,
946 uint32_t action)
947{
948 GdkDragContext *context;
949
950 g_debug (G_STRLOC ": %s source = %p action=%x",
951 G_STRFUNC, source, action);
952
953 context = gdk_wayland_drag_context_lookup_by_data_source (source);
954
955 if (!context)
956 return;
957
958 context->action = _wl_to_gdk_actions (action);
959 g_signal_emit_by_name (context, "action-changed", context->action);
960}
961
962static const struct wl_data_source_listener data_source_listener = {
963 data_source_target,
964 data_source_send,
965 data_source_cancelled,
966 data_source_dnd_drop_performed,
967 data_source_dnd_finished,
968 data_source_action,
969};
970
971static void
972primary_source_send (void *data,
973 struct gtk_primary_selection_source *source,
974 const char *mime_type,
975 int32_t fd)
976{
977 GdkWaylandSelection *wayland_selection = data;
978
979 g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
980 G_STRFUNC, source, mime_type, fd);
981
982 if (!mime_type || !wayland_selection->primary_owner)
983 {
984 close (fd);
985 return;
986 }
987
988 if (!gdk_wayland_selection_request_target (wayland_selection,
989 wayland_selection->primary_owner,
990 atoms[ATOM_PRIMARY],
991 gdk_atom_intern (mime_type, FALSE),
992 fd))
993 gdk_wayland_selection_check_write (wayland_selection);
994}
995
996static void
997primary_source_cancelled (void *data,
998 struct gtk_primary_selection_source *source)
999{
1000 GdkDisplay *display;
1001 GdkAtom atom;
1002
1003 g_debug (G_STRLOC ": %s source = %p",
1004 G_STRFUNC, source);
1005
1006 display = gdk_display_get_default ();
1007
1008 atom = atoms[ATOM_PRIMARY];
1009 gdk_selection_owner_set (NULL, atom, GDK_CURRENT_TIME, TRUE);
1010 gdk_wayland_selection_unset_data_source (display, atom);
1011}
1012
1013static const struct gtk_primary_selection_source_listener primary_source_listener = {
1014 primary_source_send,
1015 primary_source_cancelled,
1016};
1017
1018struct wl_data_source *
1019gdk_wayland_selection_get_data_source (GdkWindow *owner,
1020 GdkAtom selection)
1021{
1022 GdkDisplay *display = gdk_window_get_display (owner);
1023 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1024 gpointer source = NULL;
1025 GdkWaylandDisplay *display_wayland;
1026
1027 if (selection == atoms[ATOM_DND])
1028 {
1029 if (wayland_selection->dnd_source &&
1030 (!owner || owner == wayland_selection->dnd_owner))
1031 return wayland_selection->dnd_source;
1032 }
1033 else if (selection == atoms[ATOM_PRIMARY])
1034 {
1035 if (wayland_selection->primary_source &&
1036 (!owner || owner == wayland_selection->primary_owner))
1037 return (gpointer) wayland_selection->primary_source;
1038
1039 if (wayland_selection->primary_source)
1040 {
1041 gtk_primary_selection_source_destroy (wayland_selection->primary_source);
1042 wayland_selection->primary_source = NULL;
1043 }
1044 }
1045 else if (selection == atoms[ATOM_CLIPBOARD])
1046 {
1047 if (wayland_selection->clipboard_source &&
1048 (!owner || owner == wayland_selection->clipboard_owner))
1049 return wayland_selection->clipboard_source;
1050
1051 if (wayland_selection->clipboard_source)
1052 {
1053 wl_data_source_destroy (wayland_selection->clipboard_source);
1054 wayland_selection->clipboard_source = NULL;
1055 }
1056 }
1057 else
1058 return NULL;
1059
1060 if (!owner)
1061 return NULL;
1062
1063 display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (owner));
1064
1065 if (selection == atoms[ATOM_PRIMARY])
1066 {
1067 if (display_wayland->primary_selection_manager)
1068 {
1069 source = gtk_primary_selection_device_manager_create_source (display_wayland->primary_selection_manager);
1070 gtk_primary_selection_source_add_listener (source,
1071 &primary_source_listener,
1072 wayland_selection);
1073 }
1074 }
1075 else
1076 {
1077 source = wl_data_device_manager_create_data_source (display_wayland->data_device_manager);
1078 wl_data_source_add_listener (source,
1079 &data_source_listener,
1080 wayland_selection);
1081 }
1082
1083 if (selection == atoms[ATOM_DND])
1084 wayland_selection->dnd_source = source;
1085 else if (selection == atoms[ATOM_PRIMARY])
1086 wayland_selection->primary_source = source;
1087 else if (selection == atoms[ATOM_CLIPBOARD])
1088 wayland_selection->clipboard_source = source;
1089
1090 return source;
1091}
1092
1093void
1094gdk_wayland_selection_unset_data_source (GdkDisplay *display,
1095 GdkAtom selection)
1096{
1097 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1098
1099 if (selection == atoms[ATOM_CLIPBOARD])
1100 {
1101 GdkDevice *device;
1102
1103 device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
1104
1105 gdk_wayland_device_set_selection (device, NULL);
1106
1107 if (wayland_selection->clipboard_source)
1108 {
1109 wl_data_source_destroy (wayland_selection->clipboard_source);
1110 wayland_selection->clipboard_source = NULL;
1111 }
1112 }
1113 else if (selection == atoms[ATOM_PRIMARY])
1114 {
1115 GdkSeat *seat = gdk_display_get_default_seat (display);
1116
1117 gdk_wayland_seat_set_primary (seat, NULL);
1118
1119 if (wayland_selection->primary_source)
1120 {
1121 gtk_primary_selection_source_destroy (wayland_selection->primary_source);
1122 wayland_selection->primary_source = NULL;
1123 }
1124 }
1125 else if (selection == atoms[ATOM_DND])
1126 {
1127 wayland_selection->dnd_source = NULL;
1128 }
1129}
1130
1131GdkWindow *
1132_gdk_wayland_display_get_selection_owner (GdkDisplay *display,
1133 GdkAtom selection)
1134{
1135 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1136
1137 if (selection == atoms[ATOM_CLIPBOARD])
1138 return wayland_selection->clipboard_owner;
1139 else if (selection == atoms[ATOM_PRIMARY])
1140 return wayland_selection->primary_owner;
1141 else if (selection == atoms[ATOM_DND])
1142 return wayland_selection->dnd_owner;
1143
1144 return NULL;
1145}
1146
1147gboolean
1148_gdk_wayland_display_set_selection_owner (GdkDisplay *display,
1149 GdkWindow *owner,
1150 GdkAtom selection,
1151 guint32 time,
1152 gboolean send_event)
1153{
1154 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1155
1156 if (selection == atoms[ATOM_CLIPBOARD])
1157 {
1158 wayland_selection->clipboard_owner = owner;
1159 return TRUE;
1160 }
1161 else if (selection == atoms[ATOM_PRIMARY])
1162 {
1163 wayland_selection->primary_owner = owner;
1164 return TRUE;
1165 }
1166 else if (selection == atoms[ATOM_DND])
1167 {
1168 wayland_selection->dnd_owner = owner;
1169 return TRUE;
1170 }
1171
1172 return FALSE;
1173}
1174
1175void
1176_gdk_wayland_display_send_selection_notify (GdkDisplay *dispay,
1177 GdkWindow *requestor,
1178 GdkAtom selection,
1179 GdkAtom target,
1180 GdkAtom property,
1181 guint32 time)
1182{
1183}
1184
1185gint
1186_gdk_wayland_display_get_selection_property (GdkDisplay *display,
1187 GdkWindow *requestor,
1188 guchar **data,
1189 GdkAtom *ret_type,
1190 gint *ret_format)
1191{
1192 SelectionBuffer *buffer_data;
1193 gsize len;
1194
1195 buffer_data = gdk_wayland_selection_lookup_requestor_buffer (requestor);
1196
1197 if (!buffer_data)
1198 return 0;
1199
1200 selection_buffer_remove_requestor (buffer_data, requestor);
1201 len = buffer_data->data->len;
1202
1203 if (data)
1204 {
1205 guchar *buffer;
1206
1207 buffer = g_new0 (guchar, len + 1);
1208 memcpy (buffer, buffer_data->data->data, len);
1209 *data = buffer;
1210 }
1211
1212 if (buffer_data->target == gdk_atom_intern_static_string ("TARGETS"))
1213 {
1214 if (ret_type)
1215 *ret_type = GDK_SELECTION_TYPE_ATOM;
1216 if (ret_format)
1217 *ret_format = 32;
1218 }
1219 else
1220 {
1221 if (ret_type)
1222 *ret_type = buffer_data->target;
1223 if (ret_format)
1224 *ret_format = 8;
1225 }
1226
1227 return len;
1228}
1229
1230static void
1231emit_empty_selection_notify (GdkWindow *requestor,
1232 GdkAtom selection,
1233 GdkAtom target)
1234{
1235 GdkEvent *event;
1236
1237 event = gdk_event_new (GDK_SELECTION_NOTIFY);
1238 event->selection.window = g_object_ref (requestor);
1239 event->selection.send_event = FALSE;
1240 event->selection.selection = selection;
1241 event->selection.target = target;
1242 event->selection.property = GDK_NONE;
1243 event->selection.time = GDK_CURRENT_TIME;
1244 event->selection.requestor = g_object_ref (requestor);
1245
1246 gdk_event_put (event);
1247 gdk_event_free (event);
1248}
1249
1250void
1251_gdk_wayland_display_convert_selection (GdkDisplay *display,
1252 GdkWindow *requestor,
1253 GdkAtom selection,
1254 GdkAtom target,
1255 guint32 time)
1256{
1257 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1258 SelectionBuffer *buffer_data;
1259 gpointer offer;
1260 gchar *mimetype;
1261 GList *target_list;
1262
1263 offer = gdk_wayland_selection_get_offer (display, selection);
1264 target_list = gdk_wayland_selection_get_targets (display, selection);
1265
1266 if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
1267 {
1268 emit_empty_selection_notify (requestor, selection, target);
1269 return;
1270 }
1271
1272 mimetype = gdk_atom_name (target);
1273
1274 if (target != gdk_atom_intern_static_string ("TARGETS"))
1275 {
1276 if (!g_list_find (target_list, GDK_ATOM_TO_POINTER (target)))
1277 {
1278 emit_empty_selection_notify (requestor, selection, target);
1279 return;
1280 }
1281
1282 if (selection != atoms[ATOM_PRIMARY])
1283 wl_data_offer_accept (offer,
1284 _gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)),
1285 mimetype);
1286 }
1287
1288 buffer_data = g_hash_table_lookup (wayland_selection->selection_buffers,
1289 target);
1290
1291 if (buffer_data)
1292 selection_buffer_add_requestor (buffer_data, requestor);
1293 else
1294 {
1295 GInputStream *stream = NULL;
1296 int pipe_fd[2], natoms = 0;
1297 GdkAtom *targets = NULL;
1298
1299 if (target == gdk_atom_intern_static_string ("TARGETS"))
1300 {
1301 gint i = 0;
1302 GList *l;
1303
1304 natoms = g_list_length (target_list);
1305 targets = g_new0 (GdkAtom, natoms);
1306
1307 for (l = target_list; l; l = l->next)
1308 targets[i++] = l->data;
1309 }
1310 else
1311 {
1312 g_unix_open_pipe (pipe_fd, FD_CLOEXEC, NULL);
1313
1314 if (selection == atoms[ATOM_PRIMARY])
1315 gtk_primary_selection_offer_receive (offer, mimetype, pipe_fd[1]);
1316 else
1317 wl_data_offer_receive (offer, mimetype, pipe_fd[1]);
1318
1319 stream = g_unix_input_stream_new (pipe_fd[0], TRUE);
1320 close (pipe_fd[1]);
1321 }
1322
1323 buffer_data = selection_buffer_new (stream, selection, target);
1324 selection_buffer_add_requestor (buffer_data, requestor);
1325
1326 if (stream)
1327 g_object_unref (stream);
1328
1329 if (targets)
1330 {
1331 /* Store directly the local atoms */
1332 selection_buffer_append_data (buffer_data, targets, natoms * sizeof (GdkAtom));
1333 g_free (targets);
1334 }
1335
1336 g_hash_table_insert (wayland_selection->selection_buffers,
1337 GDK_ATOM_TO_POINTER (target),
1338 buffer_data);
1339 }
1340
1341 if (!buffer_data->stream)
1342 selection_buffer_notify (buffer_data);
1343
1344 g_free (mimetype);
1345}
1346
1347gint
1348_gdk_wayland_display_text_property_to_utf8_list (GdkDisplay *display,
1349 GdkAtom encoding,
1350 gint format,
1351 const guchar *text,
1352 gint length,
1353 gchar ***list)
1354{
1355 GPtrArray *array;
1356 const gchar *ptr;
1357 gsize chunk_len;
1358 gchar *copy;
1359 guint nitems;
1360
1361 ptr = (const gchar *) text;
1362 array = g_ptr_array_new ();
1363
1364 while (ptr < (const gchar *) &text[length])
1365 {
1366 chunk_len = strlen (ptr);
1367
1368 if (g_utf8_validate (ptr, chunk_len, NULL))
1369 {
1370 copy = g_strndup (ptr, chunk_len);
1371 g_ptr_array_add (array, copy);
1372 }
1373
1374 ptr = &ptr[chunk_len + 1];
1375 }
1376
1377 nitems = array->len;
1378 g_ptr_array_add (array, NULL);
1379
1380 if (list)
1381 *list = (gchar **) g_ptr_array_free (array, FALSE);
1382 else
1383 g_ptr_array_free (array, TRUE);
1384
1385 return nitems;
1386}
1387
1388gchar *
1389_gdk_wayland_display_utf8_to_string_target (GdkDisplay *display,
1390 const gchar *str)
1391{
1392 return NULL;
1393}
1394
1395void
1396gdk_wayland_selection_add_targets (GdkWindow *window,
1397 GdkAtom selection,
1398 guint ntargets,
1399 GdkAtom *targets)
1400{
1401 GdkDisplay *display = gdk_window_get_display (window);
1402 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1403 gpointer data_source;
1404 guint i;
1405
1406 g_return_if_fail (GDK_IS_WINDOW (window));
1407
1408 data_source = gdk_wayland_selection_get_data_source (window, selection);
1409
1410 if (!data_source)
1411 return;
1412
1413 g_array_append_vals (wayland_selection->source_targets, targets, ntargets);
1414
1415 for (i = 0; i < ntargets; i++)
1416 {
1417 gchar *mimetype = gdk_atom_name (targets[i]);
1418
1419 wl_data_source_offer (data_source, mimetype);
1420 g_free (mimetype);
1421 }
1422
1423 if (selection == atoms[ATOM_CLIPBOARD])
1424 {
1425 GdkDisplay *display;
1426 GdkDevice *device;
1427
1428 display = gdk_window_get_display (window);
1429 device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
1430 gdk_wayland_device_set_selection (device, data_source);
1431 }
1432 else if (selection == atoms[ATOM_PRIMARY])
1433 {
1434 GdkSeat *seat;
1435
1436 seat = gdk_display_get_default_seat (display);
1437 gdk_wayland_seat_set_primary (seat, data_source);
1438 }
1439}
1440
1441void
1442gdk_wayland_selection_clear_targets (GdkDisplay *display,
1443 GdkAtom selection)
1444{
1445 GdkWaylandSelection *wayland_selection = gdk_wayland_display_get_selection (display);
1446
1447 wayland_selection->requested_target = GDK_NONE;
1448 g_array_set_size (wayland_selection->source_targets, 0);
1449 gdk_wayland_selection_unset_data_source (display, selection);
1450}
1451
1452gboolean
1453gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
1454 uint32_t action)
1455{
1456 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
1457 struct wl_data_offer *offer;
1458 uint32_t all_actions = 0;
1459
1460 offer = gdk_wayland_selection_get_offer (display, atoms[ATOM_DND]);
1461
1462 if (!offer)
1463 return FALSE;
1464
1465 if (action != 0)
1466 all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
1467 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
1468 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
1469
1470 if (display_wayland->data_device_manager_version >=
1471 WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION)
1472 wl_data_offer_set_actions (offer, all_actions, action);
1473 return TRUE;
1474}
1475