Bug Summary

File:cdk/wayland/cdkselection-wayland.c
Warning:line 1019, column 3
Value stored to 'write_data' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cdkselection-wayland.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cdk/wayland -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Cdk" -D G_LOG_USE_STRUCTURED=1 -D CDK_COMPILATION -I ../.. -I ../../cdk -I ../../cdk -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cdk/wayland -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170505-43637-1 -x c cdkselection-wayland.c
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-unix1.h>
26
27#include "cdkwayland.h"
28#include "cdkprivate-wayland.h"
29#include "cdkdisplay-wayland.h"
30#include "cdkdndprivate.h"
31#include "cdkselection.h"
32#include "cdkproperty.h"
33#include "cdkprivate.h"
34
35#include <string.h>
36
37typedef struct _SelectionBuffer SelectionBuffer;
38typedef struct _SelectionData SelectionData;
39typedef struct _StoredSelection StoredSelection;
40typedef struct _AsyncWriteData AsyncWriteData;
41typedef struct _DataOfferData DataOfferData;
42
43struct _SelectionBuffer
44{
45 GInputStream *stream;
46 GCancellable *cancellable;
47 GByteArray *data;
48 GList *requestors;
49 CdkAtom selection;
50 CdkAtom target;
51 gint ref_count;
52};
53
54struct _StoredSelection
55{
56 CdkWaylandSelection *selection;
57 CdkWindow *source;
58 GCancellable *cancellable;
59 guchar *data;
60 gsize data_len;
61 CdkAtom type;
62 CdkAtom selection_atom;
63 GPtrArray *pending_writes; /* Array of AsyncWriteData */
64};
65
66struct _DataOfferData
67{
68 GDestroyNotify destroy_notify;
69 gpointer offer_data;
70 GList *targets; /* List of CdkAtom */
71};
72
73struct _AsyncWriteData
74{
75 GOutputStream *stream;
76 StoredSelection *stored_selection;
77 gsize index;
78};
79
80struct _SelectionData
81{
82 DataOfferData *offer;
83 GHashTable *buffers; /* Hashtable of target_atom->SelectionBuffer */
84};
85
86enum {
87 ATOM_PRIMARY,
88 ATOM_CLIPBOARD,
89 ATOM_DND,
90 N_ATOMS
91};
92
93static CdkAtom atoms[N_ATOMS] = { 0 };
94
95struct _CdkWaylandSelection
96{
97 /* Destination-side data */
98 SelectionData selections[N_ATOMS];
99 GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
100
101 /* Source-side data */
102 GPtrArray *stored_selections; /* Array of StoredSelection */
103 StoredSelection *current_request_selection;
104 GArray *source_targets;
105 CdkAtom requested_target;
106
107 gpointer primary_source;
108 CdkWindow *primary_owner;
109
110 struct wl_data_source *clipboard_source;
111 CdkWindow *clipboard_owner;
112
113 struct wl_data_source *dnd_source; /* Owned by the CdkDragContext */
114 CdkWindow *dnd_owner;
115};
116
117static void selection_buffer_read (SelectionBuffer *buffer);
118static void async_write_data_write (AsyncWriteData *write_data);
119static void async_write_data_free (AsyncWriteData *write_data);
120static void emit_selection_clear (CdkDisplay *display, CdkAtom selection);
121static void emit_empty_selection_notify (CdkWindow *requestor,
122 CdkAtom selection,
123 CdkAtom target);
124static void cdk_wayland_selection_handle_next_request (CdkWaylandSelection *wayland_selection);
125
126static void
127selection_buffer_notify (SelectionBuffer *buffer)
128{
129 GList *l;
130
131 for (l = buffer->requestors; l; l = l->next)
132 {
133 CdkEvent *event;
134
135 event = cdk_event_new (CDK_SELECTION_NOTIFY);
136 event->selection.window = g_object_ref (l->data)((__typeof__ (l->data)) (g_object_ref) (l->data));
137 event->selection.send_event = FALSE(0);
138 event->selection.selection = buffer->selection;
139 event->selection.target = buffer->target;
140 event->selection.property = cdk_atom_intern_static_string ("CDK_SELECTION");
141 event->selection.time = CDK_CURRENT_TIME0L;
142 event->selection.requestor = g_object_ref (l->data)((__typeof__ (l->data)) (g_object_ref) (l->data));
143
144 cdk_event_put (event);
145 cdk_event_free (event);
146 }
147}
148
149static SelectionBuffer *
150selection_buffer_new (GInputStream *stream,
151 CdkAtom selection,
152 CdkAtom target)
153{
154 SelectionBuffer *buffer;
155
156 buffer = g_new0 (SelectionBuffer, 1)((SelectionBuffer *) g_malloc0_n ((1), sizeof (SelectionBuffer
)))
;
157 buffer->stream = (stream) ? g_object_ref (stream)((__typeof__ (stream)) (g_object_ref) (stream)) : NULL((void*)0);
158 buffer->cancellable = g_cancellable_new ();
159 buffer->data = g_byte_array_new ();
160 buffer->selection = selection;
161 buffer->target = target;
162 buffer->ref_count = 1;
163
164 if (stream)
165 selection_buffer_read (buffer);
166
167 return buffer;
168}
169
170static SelectionBuffer *
171selection_buffer_ref (SelectionBuffer *buffer)
172{
173 buffer->ref_count++;
174 return buffer;
175}
176
177static void
178selection_buffer_unref (SelectionBuffer *buffer_data)
179{
180 GList *l;
181
182 buffer_data->ref_count--;
183
184 if (buffer_data->ref_count != 0)
185 return;
186
187 for (l = buffer_data->requestors; l; l = l->next)
188 {
189 emit_empty_selection_notify (l->data, buffer_data->selection,
190 buffer_data->target);
191 }
192
193 g_list_free (buffer_data->requestors);
194 buffer_data->requestors = NULL((void*)0);
195
196 if (buffer_data->cancellable)
197 g_object_unref (buffer_data->cancellable);
198
199 if (buffer_data->stream)
200 g_object_unref (buffer_data->stream);
201
202 if (buffer_data->data)
203 g_byte_array_unref (buffer_data->data);
204
205 g_free (buffer_data);
206}
207
208static void
209selection_buffer_append_data (SelectionBuffer *buffer,
210 gconstpointer data,
211 gsize len)
212{
213 g_byte_array_append (buffer->data, data, len);
214}
215
216static void
217selection_buffer_cancel_and_unref (SelectionBuffer *buffer_data)
218{
219 if (buffer_data->cancellable)
220 g_cancellable_cancel (buffer_data->cancellable);
221
222 selection_buffer_unref (buffer_data);
223}
224
225static void
226selection_buffer_add_requestor (SelectionBuffer *buffer,
227 CdkWindow *requestor)
228{
229 if (!g_list_find (buffer->requestors, requestor))
230 buffer->requestors = g_list_prepend (buffer->requestors,
231 g_object_ref (requestor)((__typeof__ (requestor)) (g_object_ref) (requestor)));
232}
233
234static gboolean
235selection_buffer_remove_requestor (SelectionBuffer *buffer,
236 CdkWindow *requestor)
237{
238 GList *link = g_list_find (buffer->requestors, requestor);
239
240 if (!link)
241 return FALSE(0);
242
243 g_object_unref (link->data);
244 buffer->requestors = g_list_delete_link (buffer->requestors, link);
245 return TRUE(!(0));
246}
247
248static inline glong
249get_buffer_size (void)
250{
251 return sysconf (_SC_PAGESIZE_SC_PAGESIZE);
252}
253
254static void
255selection_buffer_read_cb (GObject *object G_GNUC_UNUSED__attribute__ ((__unused__)),
256 GAsyncResult *result,
257 gpointer user_data)
258{
259 SelectionBuffer *buffer = user_data;
260 gboolean finished = TRUE(!(0));
261 GError *error = NULL((void*)0);
262 GBytes *bytes;
263
264 bytes = g_input_stream_read_bytes_finish (buffer->stream, result, &error);
265
266 if (bytes)
267 {
268 finished = g_bytes_get_size (bytes) == 0;
269 selection_buffer_append_data (buffer,
270 g_bytes_get_data (bytes, NULL((void*)0)),
271 g_bytes_get_size (bytes));
272 g_bytes_unref (bytes);
273 }
274
275 if (!finished)
276 selection_buffer_read (buffer);
277 else
278 {
279 if (error)
280 {
281 g_warning (G_STRLOC"cdkselection-wayland.c" ":" "281" ": error reading selection buffer: %s", error->message);
282 g_error_free (error);
283 }
284 else
285 selection_buffer_notify (buffer);
286
287 g_input_stream_close (buffer->stream, NULL((void*)0), NULL((void*)0));
288 g_clear_object (&buffer->stream)do { _Static_assert (sizeof *((&buffer->stream)) == sizeof
(gpointer), "Expression evaluates to false"); __typeof__ (((
&buffer->stream))) _pp = ((&buffer->stream)); __typeof__
(*((&buffer->stream))) _ptr = *_pp; *_pp = ((void*)0)
; if (_ptr) (g_object_unref) (_ptr); } while (0)
;
289 g_clear_object (&buffer->cancellable)do { _Static_assert (sizeof *((&buffer->cancellable)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&buffer->cancellable))) _pp = ((&buffer->cancellable
)); __typeof__ (*((&buffer->cancellable))) _ptr = *_pp
; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
290 }
291
292 selection_buffer_unref (buffer);
293}
294
295static void
296selection_buffer_read (SelectionBuffer *buffer)
297{
298 selection_buffer_ref (buffer);
299 g_input_stream_read_bytes_async (buffer->stream, get_buffer_size(),
300 G_PRIORITY_DEFAULT0,
301 buffer->cancellable, selection_buffer_read_cb,
302 buffer);
303}
304
305static DataOfferData *
306data_offer_data_new (gpointer offer,
307 GDestroyNotify destroy_notify)
308{
309 DataOfferData *info;
310
311 info = g_slice_new0 (DataOfferData)((DataOfferData*) g_slice_alloc0 (sizeof (DataOfferData)));
312 info->offer_data = offer;
313 info->destroy_notify = destroy_notify;
314
315 return info;
316}
317
318static void
319data_offer_data_free (DataOfferData *info)
320{
321 info->destroy_notify (info->offer_data);
322 g_list_free (info->targets);
323 g_slice_free (DataOfferData, info)do { if (1) g_slice_free1 (sizeof (DataOfferData), (info)); else
(void) ((DataOfferData*) 0 == (info)); } while (0)
;
324}
325
326static StoredSelection *
327stored_selection_new (CdkWaylandSelection *wayland_selection,
328 CdkWindow *source,
329 CdkAtom selection,
330 CdkAtom type)
331{
332 StoredSelection *stored_selection;
333
334 stored_selection = g_new0 (StoredSelection, 1)((StoredSelection *) g_malloc0_n ((1), sizeof (StoredSelection
)))
;
335 stored_selection->source = source;
336 stored_selection->type = type;
337 stored_selection->selection_atom = selection;
338 stored_selection->selection = wayland_selection;
339 stored_selection->cancellable = g_cancellable_new ();
340 stored_selection->pending_writes =
341 g_ptr_array_new_with_free_func ((GDestroyNotify) async_write_data_free);
342
343 return stored_selection;
344}
345
346static void
347stored_selection_add_data (StoredSelection *stored_selection,
348 CdkPropMode mode,
349 guchar *data,
350 gsize data_len)
351{
352 if (mode == CDK_PROP_MODE_REPLACE)
353 {
354 g_free (stored_selection->data);
355 stored_selection->data = g_memdup2 (data, data_len);
356 stored_selection->data_len = data_len;
357 }
358 else
359 {
360 GArray *array;
361
362 array = g_array_new (TRUE(!(0)), TRUE(!(0)), sizeof (guchar));
363 g_array_append_vals (array, stored_selection->data, stored_selection->data_len);
364
365 if (mode == CDK_PROP_MODE_APPEND)
366 g_array_append_vals (array, data, data_len);
367 else if (mode == CDK_PROP_MODE_PREPEND)
368 g_array_prepend_vals (array, data, data_len);
369
370 g_free (stored_selection->data);
371 stored_selection->data_len = array->len;
372 stored_selection->data = (guchar *) g_array_free (array, FALSE(0));
373 }
374}
375
376static void
377stored_selection_free (StoredSelection *stored_selection)
378{
379 g_cancellable_cancel (stored_selection->cancellable);
380 g_object_unref (stored_selection->cancellable);
381 g_ptr_array_unref (stored_selection->pending_writes);
382 g_free (stored_selection->data);
383 g_free (stored_selection);
384}
385
386static void
387stored_selection_notify_write (StoredSelection *stored_selection)
388{
389 gint i;
390
391 for (i = 0; i < stored_selection->pending_writes->len; i++)
392 {
393 AsyncWriteData *write_data;
394
395 write_data = g_ptr_array_index (stored_selection->pending_writes, i)((stored_selection->pending_writes)->pdata)[i];
396 async_write_data_write (write_data);
397 }
398}
399
400static void
401stored_selection_cancel_write (StoredSelection *stored_selection)
402{
403 g_cancellable_cancel (stored_selection->cancellable);
404 g_object_unref (stored_selection->cancellable);
405 stored_selection->cancellable = g_cancellable_new ();
406 g_ptr_array_set_size (stored_selection->pending_writes, 0);
407}
408
409CdkWaylandSelection *
410cdk_wayland_selection_new (void)
411{
412 CdkWaylandSelection *selection;
413 gint i;
414
415 /* init atoms */
416 atoms[ATOM_PRIMARY] = cdk_atom_intern_static_string ("PRIMARY");
417 atoms[ATOM_CLIPBOARD] = cdk_atom_intern_static_string ("CLIPBOARD");
418 atoms[ATOM_DND] = cdk_atom_intern_static_string ("CdkWaylandSelection");
419
420 selection = g_new0 (CdkWaylandSelection, 1)((CdkWaylandSelection *) g_malloc0_n ((1), sizeof (CdkWaylandSelection
)))
;
421 for (i = 0; i < G_N_ELEMENTS (selection->selections)(sizeof (selection->selections) / sizeof ((selection->selections
)[0]))
; i++)
422 {
423 selection->selections[i].buffers =
424 g_hash_table_new_full (NULL((void*)0), NULL((void*)0), NULL((void*)0),
425 (GDestroyNotify) selection_buffer_cancel_and_unref);
426 }
427
428 selection->offers =
429 g_hash_table_new_full (NULL((void*)0), NULL((void*)0), NULL((void*)0),
430 (GDestroyNotify) data_offer_data_free);
431 selection->stored_selections =
432 g_ptr_array_new_with_free_func ((GDestroyNotify) stored_selection_free);
433
434 selection->source_targets = g_array_new (FALSE(0), FALSE(0), sizeof (CdkAtom));
435 return selection;
436}
437
438static void
439primary_selection_source_destroy (gpointer primary_source)
440{
441 CdkDisplay *display = cdk_display_get_default ();
442 CdkWaylandDisplay *display_wayland = CDK_WAYLAND_DISPLAY (display)((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((display)), ((cdk_wayland_display_get_type(
)))))))
;
443
444 if (display_wayland->zwp_primary_selection_manager_v1)
445 zwp_primary_selection_source_v1_destroy (primary_source);
446 else if (display_wayland->ctk_primary_selection_manager)
447 ctk_primary_selection_source_destroy (primary_source);
448}
449
450void
451cdk_wayland_selection_free (CdkWaylandSelection *selection)
452{
453 gint i;
454
455 for (i = 0; i < G_N_ELEMENTS (selection->selections)(sizeof (selection->selections) / sizeof ((selection->selections
)[0]))
; i++)
456 g_hash_table_destroy (selection->selections[i].buffers);
457
458 g_array_unref (selection->source_targets);
459
460 g_hash_table_destroy (selection->offers);
461 g_ptr_array_unref (selection->stored_selections);
462
463 if (selection->primary_source)
464 primary_selection_source_destroy (selection->primary_source);
465 if (selection->clipboard_source)
466 wl_data_source_destroy (selection->clipboard_source);
467 if (selection->dnd_source)
468 wl_data_source_destroy (selection->dnd_source);
469
470 g_free (selection);
471}
472
473static void
474data_offer_offer (void *data,
475 struct wl_data_offer *wl_data_offer,
476 const char *type)
477{
478 CdkWaylandSelection *selection = data;
479 DataOfferData *info;
480 CdkAtom atom = cdk_atom_intern (type, FALSE(0));
481
482 info = g_hash_table_lookup (selection->offers, wl_data_offer);
483
484 if (!info || g_list_find (info->targets, atom))
485 return;
486
487 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data offer offer, offer %p, type = %s", wl_data_offer, type
); }; } while (0)
488 g_message ("data offer offer, offer %p, type = %s", wl_data_offer, type))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data offer offer, offer %p, type = %s", wl_data_offer, type
); }; } while (0)
;
489
490 info->targets = g_list_prepend (info->targets, atom);
491}
492
493static inline CdkDragAction
494_wl_to_cdk_actions (uint32_t dnd_actions)
495{
496 CdkDragAction actions = 0;
497
498 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
499 actions |= CDK_ACTION_COPY;
500 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
501 actions |= CDK_ACTION_MOVE;
502 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
503 actions |= CDK_ACTION_ASK;
504
505 return actions;
506}
507
508static void
509data_offer_source_actions (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
510 struct wl_data_offer *wl_data_offer,
511 uint32_t source_actions)
512{
513 CdkDragContext *drop_context;
514 CdkDisplay *display;
515 CdkDevice *device;
516 CdkSeat *seat;
517
518 display = cdk_display_get_default ();
519 seat = cdk_display_get_default_seat (display);
520 device = cdk_seat_get_pointer (seat);
521 drop_context = cdk_wayland_device_get_drop_context (device);
522
523 drop_context->actions = _wl_to_cdk_actions (source_actions);
524
525 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data offer source actions, offer %p, actions %d", wl_data_offer
, source_actions); }; } while (0)
526 g_message ("data offer source actions, offer %p, actions %d", wl_data_offer, source_actions))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data offer source actions, offer %p, actions %d", wl_data_offer
, source_actions); }; } while (0)
;
527
528 if (cdk_drag_context_get_dest_window (drop_context))
529 _cdk_wayland_drag_context_emit_event (drop_context, CDK_DRAG_MOTION,
530 CDK_CURRENT_TIME0L);
531}
532
533static void
534data_offer_action (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
535 struct wl_data_offer *wl_data_offer G_GNUC_UNUSED__attribute__ ((__unused__)),
536 uint32_t action)
537{
538 CdkDragContext *drop_context;
539 CdkDisplay *display;
540 CdkDevice *device;
541 CdkSeat *seat;
542
543 display = cdk_display_get_default ();
544 seat = cdk_display_get_default_seat (display);
545 device = cdk_seat_get_pointer (seat);
546 drop_context = cdk_wayland_device_get_drop_context (device);
547
548 drop_context->action = _wl_to_cdk_actions (action);
549
550 if (cdk_drag_context_get_dest_window (drop_context))
551 _cdk_wayland_drag_context_emit_event (drop_context, CDK_DRAG_MOTION,
552 CDK_CURRENT_TIME0L);
553}
554
555static const struct wl_data_offer_listener data_offer_listener = {
556 data_offer_offer,
557 data_offer_source_actions,
558 data_offer_action
559};
560
561static void
562primary_offer_offer (void *data,
563 gpointer offer,
564 const char *type)
565{
566 CdkWaylandSelection *selection = data;
567 DataOfferData *info;
568 CdkAtom atom = cdk_atom_intern (type, FALSE(0));
569
570 info = g_hash_table_lookup (selection->offers, offer);
571
572 if (!info || g_list_find (info->targets, atom))
573 return;
574
575 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary offer offer, offer %p, type = %s", offer, type); }
; } while (0)
576 g_message ("primary offer offer, offer %p, type = %s", offer, type))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary offer offer, offer %p, type = %s", offer, type); }
; } while (0)
;
577
578 info->targets = g_list_prepend (info->targets, atom);
579}
580
581static void
582ctk_primary_offer_offer (void *data,
583 struct ctk_primary_selection_offer *offer,
584 const char *type)
585{
586 primary_offer_offer (data, (gpointer) offer, type);
587}
588
589static void
590zwp_primary_offer_v1_offer (void *data,
591 struct zwp_primary_selection_offer_v1 *offer,
592 const char *type)
593{
594 primary_offer_offer (data, (gpointer) offer, type);
595}
596
597static const struct ctk_primary_selection_offer_listener ctk_primary_offer_listener = {
598 ctk_primary_offer_offer,
599};
600
601static const struct zwp_primary_selection_offer_v1_listener zwp_primary_offer_listener_v1 = {
602 zwp_primary_offer_v1_offer,
603};
604
605SelectionData *
606selection_lookup_offer_by_atom (CdkWaylandSelection *selection,
607 CdkAtom selection_atom)
608{
609 if (selection_atom == atoms[ATOM_PRIMARY])
610 return &selection->selections[ATOM_PRIMARY];
611 else if (selection_atom == atoms[ATOM_CLIPBOARD])
612 return &selection->selections[ATOM_CLIPBOARD];
613 else if (selection_atom == atoms[ATOM_DND])
614 return &selection->selections[ATOM_DND];
615 else
616 return NULL((void*)0);
617}
618
619void
620cdk_wayland_selection_ensure_offer (CdkDisplay *display,
621 struct wl_data_offer *wl_offer)
622{
623 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
624 DataOfferData *info;
625
626 info = g_hash_table_lookup (selection->offers, wl_offer);
627
628 if (!info)
629 {
630 info = data_offer_data_new (wl_offer,
631 (GDestroyNotify) wl_data_offer_destroy);
632 g_hash_table_insert (selection->offers, wl_offer, info);
633 wl_data_offer_add_listener (wl_offer,
634 &data_offer_listener,
635 selection);
636 }
637}
638
639void
640cdk_wayland_selection_ensure_primary_offer (CdkDisplay *display,
641 gpointer ctk_offer)
642{
643 CdkWaylandDisplay *display_wayland = CDK_WAYLAND_DISPLAY (display)((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((display)), ((cdk_wayland_display_get_type(
)))))))
;
644 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
645 DataOfferData *info;
646
647 info = g_hash_table_lookup (selection->offers, ctk_offer);
648
649 if (!info)
650 {
651 if (display_wayland->zwp_primary_selection_manager_v1)
652 {
653 info = data_offer_data_new (ctk_offer,
654 (GDestroyNotify) zwp_primary_selection_offer_v1_destroy);
655 g_hash_table_insert (selection->offers, ctk_offer, info);
656 zwp_primary_selection_offer_v1_add_listener (ctk_offer,
657 &zwp_primary_offer_listener_v1,
658 selection);
659 }
660 else if (display_wayland->ctk_primary_selection_manager)
661 {
662 info = data_offer_data_new (ctk_offer,
663 (GDestroyNotify) ctk_primary_selection_offer_destroy);
664 g_hash_table_insert (selection->offers, ctk_offer, info);
665 ctk_primary_selection_offer_add_listener (ctk_offer,
666 &ctk_primary_offer_listener,
667 selection);
668 }
669 }
670}
671
672void
673cdk_wayland_selection_set_offer (CdkDisplay *display,
674 CdkAtom selection_atom,
675 gpointer wl_offer)
676{
677 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
678 struct wl_data_offer *prev_offer;
679 SelectionData *selection_data;
680 DataOfferData *info;
681
682 info = g_hash_table_lookup (selection->offers, wl_offer);
683
684 prev_offer = cdk_wayland_selection_get_offer (display, selection_atom);
685
686 if (prev_offer)
687 g_hash_table_remove (selection->offers, prev_offer);
688
689 selection_data = selection_lookup_offer_by_atom (selection, selection_atom);
690
691 if (selection_data)
692 {
693 selection_data->offer = info;
694 /* Clear all buffers */
695 g_hash_table_remove_all (selection_data->buffers);
696 }
697}
698
699gpointer
700cdk_wayland_selection_get_offer (CdkDisplay *display,
701 CdkAtom selection_atom)
702{
703 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
704 const SelectionData *data;
705
706 data = selection_lookup_offer_by_atom (selection, selection_atom);
707
708 if (data && data->offer)
709 return data->offer->offer_data;
710
711 return NULL((void*)0);
712}
713
714GList *
715cdk_wayland_selection_get_targets (CdkDisplay *display,
716 CdkAtom selection_atom)
717{
718 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
719 const SelectionData *data;
720
721 data = selection_lookup_offer_by_atom (selection, selection_atom);
722
723 if (data && data->offer)
724 return data->offer->targets;
725
726 return NULL((void*)0);
727}
728
729static void
730cdk_wayland_selection_emit_request (CdkWindow *window,
731 CdkAtom selection,
732 CdkAtom target)
733{
734 CdkEvent *event;
735
736 event = cdk_event_new (CDK_SELECTION_REQUEST);
737 event->selection.window = g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
738 event->selection.send_event = FALSE(0);
739 event->selection.selection = selection;
740 event->selection.target = target;
741 event->selection.property = cdk_atom_intern_static_string ("CDK_SELECTION");
742 event->selection.time = CDK_CURRENT_TIME0L;
743 event->selection.requestor = g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
744
745 cdk_event_put (event);
746 cdk_event_free (event);
747}
748
749static AsyncWriteData *
750async_write_data_new (StoredSelection *stored_selection,
751 gint fd)
752{
753 AsyncWriteData *write_data;
754
755 write_data = g_slice_new0 (AsyncWriteData)((AsyncWriteData*) g_slice_alloc0 (sizeof (AsyncWriteData)));
756 write_data->stored_selection = stored_selection;
757 write_data->stream = g_unix_output_stream_new (fd, TRUE(!(0)));
758 g_ptr_array_add (stored_selection->pending_writes, write_data);
759
760 return write_data;
761}
762
763static void
764async_write_data_free (AsyncWriteData *write_data)
765{
766 g_object_unref (write_data->stream);
767 g_slice_free (AsyncWriteData, write_data)do { if (1) g_slice_free1 (sizeof (AsyncWriteData), (write_data
)); else (void) ((AsyncWriteData*) 0 == (write_data)); } while
(0)
;
768}
769
770static void
771async_write_data_cb (GObject *object,
772 GAsyncResult *res,
773 gpointer user_data)
774{
775 AsyncWriteData *write_data = user_data;
776 GError *error = NULL((void*)0);
777 gsize bytes_written;
778
779 bytes_written = g_output_stream_write_finish (G_OUTPUT_STREAM (object)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((g_output_stream_get_type ()))))))
,
780 res, &error);
781 if (error)
782 {
783 if (!g_error_matches (error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_CANCELLED))
784 {
785 g_warning ("Error writing selection data: %s", error->message);
786 g_ptr_array_remove_fast (write_data->stored_selection->pending_writes,
787 write_data);
788 }
789
790 g_error_free (error);
791 return;
792 }
793
794 write_data->index += bytes_written;
795
796 if (write_data->index < write_data->stored_selection->data_len)
797 {
798 /* Write the next chunk */
799 async_write_data_write (write_data);
800 }
801 else
802 {
803 g_ptr_array_remove_fast (write_data->stored_selection->pending_writes,
804 write_data);
805 }
806}
807
808static void
809async_write_data_write (AsyncWriteData *write_data)
810{
811 gsize buf_len;
812 guchar *buf;
813
814 buf = write_data->stored_selection->data;
815 buf_len = write_data->stored_selection->data_len;
816
817 g_output_stream_write_async (write_data->stream,
818 &buf[write_data->index],
819 buf_len - write_data->index,
820 G_PRIORITY_DEFAULT0,
821 write_data->stored_selection->cancellable,
822 async_write_data_cb,
823 write_data);
824}
825
826static StoredSelection *
827cdk_wayland_selection_find_stored_selection (CdkWaylandSelection *wayland_selection,
828 CdkWindow *window,
829 CdkAtom selection,
830 CdkAtom type)
831{
832 gint i;
833
834 for (i = 0; i < wayland_selection->stored_selections->len; i++)
835 {
836 StoredSelection *stored_selection;
837
838 stored_selection = g_ptr_array_index (wayland_selection->stored_selections, i)((wayland_selection->stored_selections)->pdata)[i];
839
840 if (stored_selection->source == window &&
841 stored_selection->selection_atom == selection &&
842 stored_selection->type == type)
843 return stored_selection;
844 }
845
846 return NULL((void*)0);
847}
848
849static void
850cdk_wayland_selection_reset_selection (CdkWaylandSelection *wayland_selection,
851 CdkAtom selection)
852{
853 gint i = 0;
854
855 while (i < wayland_selection->stored_selections->len)
856 {
857 StoredSelection *stored_selection;
858
859 stored_selection = g_ptr_array_index (wayland_selection->stored_selections, i)((wayland_selection->stored_selections)->pdata)[i];
860
861 if (stored_selection->selection_atom == selection)
862 {
863 if (wayland_selection->current_request_selection == stored_selection)
864 wayland_selection->current_request_selection = NULL((void*)0);
865
866 g_ptr_array_remove_index_fast (wayland_selection->stored_selections, i);
867 }
868 else
869 i++;
870 }
871}
872
873void
874cdk_wayland_selection_store (CdkWindow *window,
875 CdkAtom type,
876 CdkPropMode mode,
877 const guchar *data,
878 gint len)
879{
880 CdkDisplay *display = cdk_window_get_display (window);
881 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
882 StoredSelection *stored_selection;
883
884 if (type == cdk_atom_intern_static_string ("NULL"))
885 return;
886 if (!selection->current_request_selection)
887 return;
888
889 stored_selection = selection->current_request_selection;
890
891 if ((mode == CDK_PROP_MODE_PREPEND ||
892 mode == CDK_PROP_MODE_REPLACE) &&
893 stored_selection->data &&
894 stored_selection->pending_writes->len > 0)
895 {
896 /* If a prepend/replace action happens, all current readers are
897 * pretty much stale.
898 */
899 stored_selection_cancel_write (stored_selection);
900 }
901
902 stored_selection_add_data (stored_selection, mode, data, len);
903
904 if (stored_selection->data)
905 stored_selection_notify_write (stored_selection);
906 else
907 {
908 g_ptr_array_remove_fast (selection->stored_selections,
909 stored_selection);
910 }
911
912 /* Handle the next CDK_SELECTION_REQUEST / store, if any */
913 selection->current_request_selection = NULL((void*)0);
914 cdk_wayland_selection_handle_next_request (selection);
915}
916
917static SelectionBuffer *
918cdk_wayland_selection_lookup_requestor_buffer (CdkWindow *requestor)
919{
920 CdkDisplay *display = cdk_window_get_display (requestor);
921 CdkWaylandSelection *selection = cdk_wayland_display_get_selection (display);
922 SelectionBuffer *buffer_data;
923 GHashTableIter iter;
924 gint i;
925
926 for (i = 0; i < G_N_ELEMENTS (selection->selections)(sizeof (selection->selections) / sizeof ((selection->selections
)[0]))
; i++)
927 {
928 g_hash_table_iter_init (&iter, selection->selections[i].buffers);
929
930 while (g_hash_table_iter_next (&iter, NULL((void*)0), (gpointer*) &buffer_data))
931 {
932 if (g_list_find (buffer_data->requestors, requestor))
933 return buffer_data;
934 }
935 }
936
937 return NULL((void*)0);
938}
939
940static gboolean
941cdk_wayland_selection_source_handles_target (CdkWaylandSelection *wayland_selection,
942 CdkAtom target)
943{
944 CdkAtom atom;
945 guint i;
946
947 if (target == CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
948 return FALSE(0);
949
950 for (i = 0; i < wayland_selection->source_targets->len; i++)
951 {
952 atom = g_array_index (wayland_selection->source_targets, CdkAtom, i)(((CdkAtom*) (void *) (wayland_selection->source_targets)->
data) [(i)])
;
953
954 if (atom == target)
955 return TRUE(!(0));
956 }
957
958 return FALSE(0);
959}
960
961static void
962cdk_wayland_selection_handle_next_request (CdkWaylandSelection *wayland_selection)
963{
964 gint i;
965
966 for (i = 0; i < wayland_selection->stored_selections->len; i++)
967 {
968 StoredSelection *stored_selection;
969
970 stored_selection = g_ptr_array_index (wayland_selection->stored_selections, i)((wayland_selection->stored_selections)->pdata)[i];
971
972 if (!stored_selection->data)
973 {
974 cdk_wayland_selection_emit_request (stored_selection->source,
975 stored_selection->selection_atom,
976 stored_selection->type);
977 wayland_selection->current_request_selection = stored_selection;
978 break;
979 }
980 }
981}
982
983static gboolean
984cdk_wayland_selection_request_target (CdkWaylandSelection *wayland_selection,
985 CdkWindow *window,
986 CdkAtom selection,
987 CdkAtom target,
988 gint fd)
989{
990 StoredSelection *stored_selection;
991 AsyncWriteData *write_data;
992
993 if (!window ||
994 !cdk_wayland_selection_source_handles_target (wayland_selection, target))
995 {
996 close (fd);
997 return FALSE(0);
998 }
999
1000 stored_selection =
1001 cdk_wayland_selection_find_stored_selection (wayland_selection, window,
1002 selection, target);
1003
1004 if (stored_selection && stored_selection->data)
1005 {
1006 /* Fast path, we already have the type cached */
1007 write_data = async_write_data_new (stored_selection, fd);
1008 async_write_data_write (write_data);
1009 return TRUE(!(0));
1010 }
1011
1012 if (!stored_selection)
1013 {
1014 stored_selection = stored_selection_new (wayland_selection, window,
1015 selection, target);
1016 g_ptr_array_add (wayland_selection->stored_selections, stored_selection);
1017 }
1018
1019 write_data = async_write_data_new (stored_selection, fd);
Value stored to 'write_data' is never read
1020
1021 if (!wayland_selection->current_request_selection)
1022 cdk_wayland_selection_handle_next_request (wayland_selection);
1023
1024 return TRUE(!(0));
1025}
1026
1027static void
1028data_source_target (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
1029 struct wl_data_source *source,
1030 const char *mime_type)
1031{
1032 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source target, source = %p, mime_type = %s", source, mime_type
); }; } while (0)
1033 g_message ("data source target, source = %p, mime_type = %s",do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source target, source = %p, mime_type = %s", source, mime_type
); }; } while (0)
1034 source, mime_type))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source target, source = %p, mime_type = %s", source, mime_type
); }; } while (0)
;
1035}
1036
1037static void
1038data_source_send (void *data,
1039 struct wl_data_source *source,
1040 const char *mime_type,
1041 int32_t fd)
1042{
1043 CdkWaylandSelection *wayland_selection = data;
1044 CdkWindow *window;
1045 CdkAtom selection;
1046
1047 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source send, source = %p, mime_type = %s, fd = %d", source
, mime_type, fd); }; } while (0)
1048 g_message ("data source send, source = %p, mime_type = %s, fd = %d",do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source send, source = %p, mime_type = %s, fd = %d", source
, mime_type, fd); }; } while (0)
1049 source, mime_type, fd))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source send, source = %p, mime_type = %s, fd = %d", source
, mime_type, fd); }; } while (0)
;
1050
1051 if (!mime_type)
1052 {
1053 close (fd);
1054 return;
1055 }
1056
1057 if (source == wayland_selection->dnd_source)
1058 {
1059 window = wayland_selection->dnd_owner;
1060 selection = atoms[ATOM_DND];
1061 }
1062 else if (source == wayland_selection->clipboard_source)
1063 {
1064 window = wayland_selection->clipboard_owner;
1065 selection = atoms[ATOM_CLIPBOARD];
1066 }
1067 else
1068 {
1069 close (fd);
1070 return;
1071 }
1072
1073 if (!window)
1074 return;
1075
1076 cdk_wayland_selection_request_target (wayland_selection, window,
1077 selection,
1078 cdk_atom_intern (mime_type, FALSE(0)),
1079 fd);
1080}
1081
1082static void
1083data_source_cancelled (void *data,
1084 struct wl_data_source *source)
1085{
1086 CdkWaylandSelection *wayland_selection = data;
1087 CdkDragContext *context;
1088 CdkDisplay *display;
1089 CdkAtom atom;
1090
1091 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source cancelled, source = %p", source); }; } while (
0)
1092 g_message ("data source cancelled, source = %p", source))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source cancelled, source = %p", source); }; } while (
0)
;
1093
1094 display = cdk_display_get_default ();
1095
1096 if (source == wayland_selection->dnd_source)
1097 atom = atoms[ATOM_DND];
1098 else if (source == wayland_selection->clipboard_source)
1099 atom = atoms[ATOM_CLIPBOARD];
1100 else
1101 return;
1102
1103 context = cdk_wayland_drag_context_lookup_by_data_source (source);
1104
1105 if (context)
1106 cdk_drag_context_cancel (context, CDK_DRAG_CANCEL_ERROR);
1107
1108 emit_selection_clear (display, atom);
1109 cdk_selection_owner_set (NULL((void*)0), atom, CDK_CURRENT_TIME0L, FALSE(0));
1110 cdk_wayland_selection_unset_data_source (display, atom);
1111}
1112
1113static void
1114data_source_dnd_drop_performed (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
1115 struct wl_data_source *source)
1116{
1117 CdkDragContext *context;
1118
1119 context = cdk_wayland_drag_context_lookup_by_data_source (source);
1120
1121 if (!context)
1122 return;
1123
1124 g_signal_emit_by_name (context, "drop-performed", CDK_CURRENT_TIME0L);
1125}
1126
1127static void
1128data_source_dnd_finished (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
1129 struct wl_data_source *source)
1130{
1131 CdkDisplay *display = cdk_display_get_default ();
1132 CdkDragContext *context;
1133
1134 context = cdk_wayland_drag_context_lookup_by_data_source (source);
1135
1136 if (!context)
1137 return;
1138
1139 if (context->action == CDK_ACTION_MOVE)
1140 {
1141 cdk_wayland_selection_emit_request (context->source_window,
1142 atoms[ATOM_DND],
1143 cdk_atom_intern_static_string ("DELETE"));
1144 }
1145
1146 g_signal_emit_by_name (context, "dnd-finished");
1147 cdk_selection_owner_set (NULL((void*)0), atoms[ATOM_DND], CDK_CURRENT_TIME0L, TRUE(!(0)));
1148 cdk_wayland_selection_clear_targetscdk_wayland_selection_clear_targets_libctk_only (display, atoms[ATOM_DND]);
1149}
1150
1151static void
1152data_source_action (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
1153 struct wl_data_source *source,
1154 uint32_t action)
1155{
1156 CdkDragContext *context;
1157
1158 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source action, source = %p action=%x", source, action
); }; } while (0)
1159 g_message ("data source action, source = %p action=%x",do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source action, source = %p action=%x", source, action
); }; } while (0)
1160 source, action))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("data source action, source = %p action=%x", source, action
); }; } while (0)
;
1161
1162 context = cdk_wayland_drag_context_lookup_by_data_source (source);
1163
1164 if (!context)
1165 return;
1166
1167 context->action = _wl_to_cdk_actions (action);
1168 g_signal_emit_by_name (context, "action-changed", context->action);
1169}
1170
1171static const struct wl_data_source_listener data_source_listener = {
1172 data_source_target,
1173 data_source_send,
1174 data_source_cancelled,
1175 data_source_dnd_drop_performed,
1176 data_source_dnd_finished,
1177 data_source_action,
1178};
1179
1180static void
1181primary_source_send (void *data,
1182 gpointer source,
1183 const char *mime_type,
1184 int32_t fd)
1185{
1186 CdkWaylandSelection *wayland_selection = data;
1187
1188 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary source send, source = %p, mime_type = %s, fd = %d"
, source, mime_type, fd); }; } while (0)
1189 g_message ("primary source send, source = %p, mime_type = %s, fd = %d",do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary source send, source = %p, mime_type = %s, fd = %d"
, source, mime_type, fd); }; } while (0)
1190 source, mime_type, fd))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary source send, source = %p, mime_type = %s, fd = %d"
, source, mime_type, fd); }; } while (0)
;
1191
1192 if (!mime_type || !wayland_selection->primary_owner)
1193 {
1194 close (fd);
1195 return;
1196 }
1197
1198 cdk_wayland_selection_request_target (wayland_selection,
1199 wayland_selection->primary_owner,
1200 atoms[ATOM_PRIMARY],
1201 cdk_atom_intern (mime_type, FALSE(0)),
1202 fd);
1203}
1204
1205static void
1206ctk_primary_source_send (void *data,
1207 struct ctk_primary_selection_source *source,
1208 const char *mime_type,
1209 int32_t fd)
1210{
1211 primary_source_send (data, (gpointer) source, mime_type, fd);
1212}
1213
1214static void
1215zwp_primary_source_v1_send (void *data,
1216 struct zwp_primary_selection_source_v1 *source,
1217 const char *mime_type,
1218 int32_t fd)
1219{
1220 primary_source_send (data, (gpointer) source, mime_type, fd);
1221}
1222
1223static void
1224primary_source_cancelled (void *data G_GNUC_UNUSED__attribute__ ((__unused__)),
1225 gpointer source)
1226{
1227 CdkDisplay *display;
1228 CdkAtom atom;
1229
1230 CDK_NOTE (EVENTS,do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary source cancelled, source = %p", source); }; } while
(0)
1231 g_message ("primary source cancelled, source = %p", source))do { if ((_cdk_debug_flags & CDK_DEBUG_EVENTS)) { g_message
("primary source cancelled, source = %p", source); }; } while
(0)
;
1232
1233 display = cdk_display_get_default ();
1234
1235 atom = atoms[ATOM_PRIMARY];
1236 emit_selection_clear (display, atom);
1237 cdk_selection_owner_set (NULL((void*)0), atom, CDK_CURRENT_TIME0L, FALSE(0));
1238 cdk_wayland_selection_unset_data_source (display, atom);
1239}
1240
1241static void
1242ctk_primary_source_cancelled (void *data,
1243 struct ctk_primary_selection_source *source)
1244{
1245 primary_source_cancelled (data, source);
1246}
1247
1248static void
1249zwp_primary_source_v1_cancelled (void *data,
1250 struct zwp_primary_selection_source_v1 *source)
1251{
1252 primary_source_cancelled (data, source);
1253}
1254
1255static const struct ctk_primary_selection_source_listener ctk_primary_source_listener = {
1256 ctk_primary_source_send,
1257 ctk_primary_source_cancelled,
1258};
1259
1260static const struct zwp_primary_selection_source_v1_listener zwp_primary_source_v1_listener = {
1261 zwp_primary_source_v1_send,
1262 zwp_primary_source_v1_cancelled,
1263};
1264
1265struct wl_data_source *
1266cdk_wayland_selection_get_data_source (CdkWindow *owner,
1267 CdkAtom selection)
1268{
1269 CdkDisplay *display = cdk_window_get_display (owner);
1270 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1271 gpointer source = NULL((void*)0);
1272 CdkWaylandDisplay *display_wayland;
1273
1274 if (selection == atoms[ATOM_DND])
1275 {
1276 if (wayland_selection->dnd_source &&
1277 (!owner || owner == wayland_selection->dnd_owner))
1278 return wayland_selection->dnd_source;
1279 }
1280 else if (selection == atoms[ATOM_PRIMARY])
1281 {
1282 if (wayland_selection->primary_source &&
1283 (!owner || owner == wayland_selection->primary_owner))
1284 return wayland_selection->primary_source;
1285
1286 if (wayland_selection->primary_source)
1287 {
1288 primary_selection_source_destroy (wayland_selection->primary_source);
1289 wayland_selection->primary_source = NULL((void*)0);
1290 }
1291 }
1292 else if (selection == atoms[ATOM_CLIPBOARD])
1293 {
1294 if (wayland_selection->clipboard_source &&
1295 (!owner || owner == wayland_selection->clipboard_owner))
1296 return wayland_selection->clipboard_source;
1297
1298 if (wayland_selection->clipboard_source)
1299 {
1300 wl_data_source_destroy (wayland_selection->clipboard_source);
1301 wayland_selection->clipboard_source = NULL((void*)0);
1302 }
1303 }
1304 else
1305 return NULL((void*)0);
1306
1307 if (!owner)
1308 return NULL((void*)0);
1309
1310 display_wayland = CDK_WAYLAND_DISPLAY (cdk_window_get_display (owner))((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((cdk_window_get_display (owner))), ((cdk_wayland_display_get_type
()))))))
;
1311
1312 if (selection == atoms[ATOM_PRIMARY])
1313 {
1314 if (display_wayland->zwp_primary_selection_manager_v1)
1315 {
1316 source = zwp_primary_selection_device_manager_v1_create_source (display_wayland->zwp_primary_selection_manager_v1);
1317 zwp_primary_selection_source_v1_add_listener (source,
1318 &zwp_primary_source_v1_listener,
1319 wayland_selection);
1320 }
1321 else if (display_wayland->ctk_primary_selection_manager)
1322 {
1323 source = ctk_primary_selection_device_manager_create_source (display_wayland->ctk_primary_selection_manager);
1324 ctk_primary_selection_source_add_listener (source,
1325 &ctk_primary_source_listener,
1326 wayland_selection);
1327 }
1328 }
1329 else
1330 {
1331 source = wl_data_device_manager_create_data_source (display_wayland->data_device_manager);
1332 wl_data_source_add_listener (source,
1333 &data_source_listener,
1334 wayland_selection);
1335 }
1336
1337 if (selection == atoms[ATOM_DND])
1338 wayland_selection->dnd_source = source;
1339 else if (selection == atoms[ATOM_PRIMARY])
1340 wayland_selection->primary_source = source;
1341 else if (selection == atoms[ATOM_CLIPBOARD])
1342 wayland_selection->clipboard_source = source;
1343
1344 return source;
1345}
1346
1347void
1348cdk_wayland_selection_unset_data_source (CdkDisplay *display,
1349 CdkAtom selection)
1350{
1351 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1352
1353 if (selection == atoms[ATOM_CLIPBOARD])
1354 {
1355 if (wayland_selection->clipboard_source)
1356 {
1357 wl_data_source_destroy (wayland_selection->clipboard_source);
1358 wayland_selection->clipboard_source = NULL((void*)0);
1359 }
1360 }
1361 else if (selection == atoms[ATOM_PRIMARY])
1362 {
1363 if (wayland_selection->primary_source)
1364 {
1365 primary_selection_source_destroy (wayland_selection->primary_source);
1366 wayland_selection->primary_source = NULL((void*)0);
1367 }
1368 }
1369 else if (selection == atoms[ATOM_DND])
1370 {
1371 wayland_selection->dnd_source = NULL((void*)0);
1372 }
1373}
1374
1375CdkWindow *
1376_cdk_wayland_display_get_selection_owner (CdkDisplay *display,
1377 CdkAtom selection)
1378{
1379 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1380
1381 if (selection == atoms[ATOM_CLIPBOARD])
1382 return wayland_selection->clipboard_owner;
1383 else if (selection == atoms[ATOM_PRIMARY])
1384 return wayland_selection->primary_owner;
1385 else if (selection == atoms[ATOM_DND])
1386 return wayland_selection->dnd_owner;
1387
1388 return NULL((void*)0);
1389}
1390
1391gboolean
1392_cdk_wayland_display_set_selection_owner (CdkDisplay *display,
1393 CdkWindow *owner,
1394 CdkAtom selection,
1395 guint32 time G_GNUC_UNUSED__attribute__ ((__unused__)),
1396 gboolean send_event)
1397{
1398 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1399 CdkSeat *seat = cdk_display_get_default_seat (display);
1400
1401 cdk_wayland_selection_reset_selection (wayland_selection, selection);
1402
1403 if (selection == atoms[ATOM_CLIPBOARD])
1404 {
1405 wayland_selection->clipboard_owner = owner;
1406 if (send_event && !owner)
1407 {
1408 cdk_wayland_seat_set_selection (seat, NULL((void*)0));
1409 cdk_wayland_selection_unset_data_source (display, selection);
1410 }
1411 return TRUE(!(0));
1412 }
1413 else if (selection == atoms[ATOM_PRIMARY])
1414 {
1415 wayland_selection->primary_owner = owner;
1416 if (send_event && !owner)
1417 {
1418 cdk_wayland_seat_set_primary (seat, NULL((void*)0));
1419 cdk_wayland_selection_unset_data_source (display, selection);
1420 }
1421 return TRUE(!(0));
1422 }
1423 else if (selection == atoms[ATOM_DND])
1424 {
1425 wayland_selection->dnd_owner = owner;
1426 return TRUE(!(0));
1427 }
1428
1429 return FALSE(0);
1430}
1431
1432void
1433_cdk_wayland_display_send_selection_notify (CdkDisplay *display,
1434 CdkWindow *requestor G_GNUC_UNUSED__attribute__ ((__unused__)),
1435 CdkAtom selection G_GNUC_UNUSED__attribute__ ((__unused__)),
1436 CdkAtom target G_GNUC_UNUSED__attribute__ ((__unused__)),
1437 CdkAtom property,
1438 guint32 time G_GNUC_UNUSED__attribute__ ((__unused__)))
1439{
1440 CdkWaylandSelection *wayland_selection;
1441
1442 if (property != CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
1443 return;
1444
1445 wayland_selection = cdk_wayland_display_get_selection (display);
1446
1447 if (!wayland_selection->current_request_selection)
1448 return;
1449
1450 g_ptr_array_remove_fast (wayland_selection->stored_selections,
1451 wayland_selection->current_request_selection);
1452
1453 /* Handle the next CDK_SELECTION_REQUEST / store, if any */
1454 wayland_selection->current_request_selection = NULL((void*)0);
1455 cdk_wayland_selection_handle_next_request (wayland_selection);
1456}
1457
1458gint
1459_cdk_wayland_display_get_selection_property (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
1460 CdkWindow *requestor,
1461 guchar **data,
1462 CdkAtom *ret_type,
1463 gint *ret_format)
1464{
1465 SelectionBuffer *buffer_data;
1466 gsize len;
1467
1468 buffer_data = cdk_wayland_selection_lookup_requestor_buffer (requestor);
1469
1470 if (!buffer_data)
1471 return 0;
1472
1473 selection_buffer_remove_requestor (buffer_data, requestor);
1474 len = buffer_data->data->len;
1475
1476 if (data)
1477 {
1478 guchar *buffer;
1479
1480 buffer = g_new0 (guchar, len + 1)((guchar *) g_malloc0_n ((len + 1), sizeof (guchar)));
1481 memcpy (buffer, buffer_data->data->data, len);
1482 *data = buffer;
1483 }
1484
1485 if (buffer_data->target == cdk_atom_intern_static_string ("TARGETS"))
1486 {
1487 if (ret_type)
1488 *ret_type = CDK_SELECTION_TYPE_ATOM((CdkAtom)((gpointer) (gulong) (4)));
1489 if (ret_format)
1490 *ret_format = 32;
1491 }
1492 else
1493 {
1494 if (ret_type)
1495 *ret_type = buffer_data->target;
1496 if (ret_format)
1497 *ret_format = 8;
1498 }
1499
1500 return len;
1501}
1502
1503static void
1504emit_empty_selection_notify (CdkWindow *requestor,
1505 CdkAtom selection,
1506 CdkAtom target)
1507{
1508 CdkEvent *event;
1509
1510 event = cdk_event_new (CDK_SELECTION_NOTIFY);
1511 event->selection.window = g_object_ref (requestor)((__typeof__ (requestor)) (g_object_ref) (requestor));
1512 event->selection.send_event = FALSE(0);
1513 event->selection.selection = selection;
1514 event->selection.target = target;
1515 event->selection.property = CDK_NONE((CdkAtom)((gpointer) (gulong) (0)));
1516 event->selection.time = CDK_CURRENT_TIME0L;
1517 event->selection.requestor = g_object_ref (requestor)((__typeof__ (requestor)) (g_object_ref) (requestor));
1518
1519 cdk_event_put (event);
1520 cdk_event_free (event);
1521}
1522
1523static void
1524emit_selection_clear (CdkDisplay *display,
1525 CdkAtom selection)
1526{
1527 CdkEvent *event;
1528 CdkWindow *window;
1529
1530 event = cdk_event_new (CDK_SELECTION_CLEAR);
1531 event->selection.selection = selection;
1532 event->selection.time = CDK_CURRENT_TIME0L;
1533
1534 window = _cdk_wayland_display_get_selection_owner (display, selection);
1535 if (window != NULL((void*)0))
1536 {
1537 event->selection.window = g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
1538 event->selection.requestor = g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window));
1539 }
1540
1541 cdk_event_put (event);
1542 cdk_event_free (event);
1543}
1544
1545void
1546_cdk_wayland_display_convert_selection (CdkDisplay *display,
1547 CdkWindow *requestor,
1548 CdkAtom selection,
1549 CdkAtom target,
1550 guint32 time G_GNUC_UNUSED__attribute__ ((__unused__)))
1551{
1552 CdkWaylandDisplay *display_wayland = CDK_WAYLAND_DISPLAY (display)((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((display)), ((cdk_wayland_display_get_type(
)))))))
;
1553 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1554 const SelectionData *selection_data;
1555 SelectionBuffer *buffer_data;
1556 gpointer offer;
1557 gchar *mimetype;
1558 GList *target_list;
1559
1560 selection_data = selection_lookup_offer_by_atom (wayland_selection, selection);
1561 if (!selection_data)
1562 {
1563 emit_empty_selection_notify (requestor, selection, target);
1564 return;
1565 }
1566
1567 offer = cdk_wayland_selection_get_offer (display, selection);
1568 target_list = cdk_wayland_selection_get_targets (display, selection);
1569
1570 if (!offer || target == cdk_atom_intern_static_string ("DELETE"))
1571 {
1572 emit_empty_selection_notify (requestor, selection, target);
1573 return;
1574 }
1575
1576 mimetype = cdk_atom_name (target);
1577
1578 if (target != cdk_atom_intern_static_string ("TARGETS"))
1579 {
1580 if (!g_list_find (target_list, CDK_ATOM_TO_POINTER (target)(target)))
1581 {
1582 emit_empty_selection_notify (requestor, selection, target);
1583 return;
1584 }
1585
1586 if (selection != atoms[ATOM_PRIMARY])
1587 wl_data_offer_accept (offer,
1588 _cdk_wayland_display_get_serial (CDK_WAYLAND_DISPLAY (display)((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((display)), ((cdk_wayland_display_get_type(
)))))))
),
1589 mimetype);
1590 }
1591
1592 buffer_data = g_hash_table_lookup (selection_data->buffers, target);
1593
1594 if (buffer_data)
1595 selection_buffer_add_requestor (buffer_data, requestor);
1596 else
1597 {
1598 GInputStream *stream = NULL((void*)0);
1599 int natoms = 0;
1600 CdkAtom *targets = NULL((void*)0);
1601
1602 if (target == cdk_atom_intern_static_string ("TARGETS"))
1603 {
1604 gint i = 0;
1605 GList *l;
1606
1607 natoms = g_list_length (target_list);
1608 targets = g_new0 (CdkAtom, natoms)((CdkAtom *) g_malloc0_n ((natoms), sizeof (CdkAtom)));
1609
1610 for (l = target_list; l; l = l->next)
1611 targets[i++] = l->data;
1612 }
1613 else
1614 {
1615 int pipe_fd[2];
1616
1617 g_unix_open_pipe (pipe_fd, FD_CLOEXEC1, NULL((void*)0));
1618
1619 if (selection == atoms[ATOM_PRIMARY])
1620 {
1621 if (display_wayland->zwp_primary_selection_manager_v1)
1622 zwp_primary_selection_offer_v1_receive (offer, mimetype, pipe_fd[1]);
1623 else if (display_wayland->ctk_primary_selection_manager)
1624 ctk_primary_selection_offer_receive (offer, mimetype, pipe_fd[1]);
1625 }
1626 else
1627 {
1628 wl_data_offer_receive (offer, mimetype, pipe_fd[1]);
1629 }
1630
1631 stream = g_unix_input_stream_new (pipe_fd[0], TRUE(!(0)));
1632 close (pipe_fd[1]);
1633 }
1634
1635 buffer_data = selection_buffer_new (stream, selection, target);
1636 selection_buffer_add_requestor (buffer_data, requestor);
1637
1638 if (stream)
1639 g_object_unref (stream);
1640
1641 if (targets)
1642 {
1643 /* Store directly the local atoms */
1644 selection_buffer_append_data (buffer_data, targets, natoms * sizeof (CdkAtom));
1645 g_free (targets);
1646 }
1647
1648 g_hash_table_insert (selection_data->buffers,
1649 CDK_ATOM_TO_POINTER (target)(target),
1650 buffer_data);
1651 }
1652
1653 if (!buffer_data->stream)
1654 selection_buffer_notify (buffer_data);
1655
1656 g_free (mimetype);
1657}
1658
1659gint
1660_cdk_wayland_display_text_property_to_utf8_list (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
1661 CdkAtom encoding G_GNUC_UNUSED__attribute__ ((__unused__)),
1662 gint format G_GNUC_UNUSED__attribute__ ((__unused__)),
1663 const guchar *text,
1664 gint length,
1665 gchar ***list)
1666{
1667 GPtrArray *array;
1668 const gchar *ptr;
1669 gsize chunk_len;
1670 gchar *copy;
1671 guint nitems;
1672
1673 ptr = (const gchar *) text;
1674 array = g_ptr_array_new ();
1675
1676 while (ptr < (const gchar *) &text[length])
1677 {
1678 chunk_len = strlen (ptr);
1679
1680 if (g_utf8_validate (ptr, chunk_len, NULL((void*)0)))
1681 {
1682 copy = g_strndup (ptr, chunk_len);
1683 g_ptr_array_add (array, copy);
1684 }
1685
1686 ptr = &ptr[chunk_len + 1];
1687 }
1688
1689 nitems = array->len;
1690 g_ptr_array_add (array, NULL((void*)0));
1691
1692 if (list)
1693 *list = (gchar **) g_ptr_array_free (array, FALSE(0));
1694 else
1695 g_ptr_array_free (array, TRUE(!(0)));
1696
1697 return nitems;
1698}
1699
1700/* This function has been copied straight from the x11 backend */
1701static gchar *
1702sanitize_utf8 (const gchar *src,
1703 gboolean return_latin1)
1704{
1705 gint len = strlen (src);
1706 GString *result = g_string_sized_new (len);
1707 const gchar *p = src;
1708
1709 while (*p)
1710 {
1711 if (*p == '\r')
1712 {
1713 p++;
1714 if (*p == '\n')
1715 p++;
1716
1717 g_string_append_c (result, '\n')g_string_append_c_inline (result, '\n');
1718 }
1719 else
1720 {
1721 gunichar ch = g_utf8_get_char (p);
1722
1723 if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
1724 {
1725 if (return_latin1)
1726 {
1727 if (ch <= 0xff)
1728 g_string_append_c (result, ch)g_string_append_c_inline (result, ch);
1729 else
1730 g_string_append_printf (result,
1731 ch < 0x10000 ? "\\u%04x" : "\\U%08x",
1732 ch);
1733 }
1734 else
1735 {
1736 char buf[7];
1737 gint buflen;
1738
1739 buflen = g_unichar_to_utf8 (ch, buf);
1740 g_string_append_len (result, buf, buflen)g_string_append_len_inline (result, buf, buflen);
1741 }
1742 }
1743
1744 p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
1745 }
1746 }
1747
1748 return g_string_free (result, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((result
), ((0))) : g_string_free_and_steal (result)) : (g_string_free
) ((result), ((0))))
;
1749}
1750
1751gchar *
1752_cdk_wayland_display_utf8_to_string_target (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
1753 const gchar *str)
1754{
1755 /* This is mainly needed when interfacing with old clients through
1756 * Xwayland, the STRING target could be used, and passed as-is
1757 * by the compositor.
1758 *
1759 * There's already some handling of this atom (aka "mimetype" in
1760 * this backend) in common code, so we end up in this vfunc.
1761 */
1762 return sanitize_utf8 (str, TRUE(!(0)));
1763}
1764
1765void
1766cdk_wayland_selection_add_targetscdk_wayland_selection_add_targets_libctk_only (CdkWindow *window,
1767 CdkAtom selection,
1768 guint ntargets,
1769 CdkAtom *targets)
1770{
1771 CdkDisplay *display = cdk_window_get_display (window);
1772 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1773 gpointer data_source;
1774 guint i;
1775
1776 g_return_if_fail (CDK_IS_WINDOW (window))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((window)); GType __t = ((cdk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__
)), "CDK_IS_WINDOW (window)"); return; } } while (0)
;
1777
1778 data_source = cdk_wayland_selection_get_data_source (window, selection);
1779
1780 if (!data_source)
1781 return;
1782
1783 g_array_append_vals (wayland_selection->source_targets, targets, ntargets);
1784
1785 for (i = 0; i < ntargets; i++)
1786 {
1787 gchar *mimetype = cdk_atom_name (targets[i]);
1788
1789 wl_data_source_offer (data_source, mimetype);
1790 g_free (mimetype);
1791 }
1792
1793 if (selection == atoms[ATOM_CLIPBOARD])
1794 {
1795 CdkSeat *seat;
1796
1797 seat = cdk_display_get_default_seat (display);
1798 cdk_wayland_seat_set_selection (seat, data_source);
1799 }
1800 else if (selection == atoms[ATOM_PRIMARY])
1801 {
1802 CdkSeat *seat;
1803
1804 seat = cdk_display_get_default_seat (display);
1805 cdk_wayland_seat_set_primary (seat, data_source);
1806 }
1807}
1808
1809void
1810cdk_wayland_selection_clear_targetscdk_wayland_selection_clear_targets_libctk_only (CdkDisplay *display,
1811 CdkAtom selection)
1812{
1813 CdkWaylandSelection *wayland_selection = cdk_wayland_display_get_selection (display);
1814
1815 wayland_selection->requested_target = CDK_NONE((CdkAtom)((gpointer) (gulong) (0)));
1816 g_array_set_size (wayland_selection->source_targets, 0);
1817 cdk_wayland_selection_unset_data_source (display, selection);
1818}
1819
1820gboolean
1821cdk_wayland_selection_set_current_offer_actions (CdkDisplay *display,
1822 uint32_t action)
1823{
1824 CdkWaylandDisplay *display_wayland = CDK_WAYLAND_DISPLAY (display)((((CdkWaylandDisplay*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((display)), ((cdk_wayland_display_get_type(
)))))))
;
1825 struct wl_data_offer *offer;
1826 uint32_t all_actions = 0;
1827
1828 offer = cdk_wayland_selection_get_offer (display, atoms[ATOM_DND]);
1829
1830 if (!offer)
1831 return FALSE(0);
1832
1833 if (action != 0)
1834 all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
1835 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
1836 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
1837
1838 if (display_wayland->data_device_manager_version >=
1839 WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION3)
1840 wl_data_offer_set_actions (offer, all_actions, action);
1841 return TRUE(!(0));
1842}