1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2000 Red Hat, Inc.
3 * Copyright (C) 2004 Nokia Corporation
4 * Copyright (C) 2006-2008 Imendio AB
5 * Copyright (C) 2011-2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
25 #include "gtkclipboard.h"
26 #include "gtkinvisible.h"
28 #include "gtkmarshalers.h"
30 #include "gtktextbuffer.h"
31 #include "gtkselectionprivate.h"
33 #include "../gdk/gdk.h"
34 #include "../gdk/wayland/gdkwayland.h"
41 typedef struct _GtkClipboardClass GtkClipboardClass;
43 typedef struct _SetContentClosure SetContentClosure;
46 GObject parent_instance;
53 SetContentClosure *last_closure;
56 struct _GtkClipboardClass
58 GObjectClass parent_class;
60 void (*owner_change) (GtkClipboard *clipboard,
61 GdkEventOwnerChange *event);
64 static void gtk_clipboard_class_init (GtkClipboardClass *class);
65 static void gtk_clipboard_finalize (GObject *object);
66 static void gtk_clipboard_owner_change (GtkClipboard *clipboard,
67 GdkEventOwnerChange *event);
69 static GObjectClass *parent_class;
70 static guint clipboard_signals[LAST_SIGNAL] = { 0 };
73 gtk_clipboard_get_type (void)
75 static GType clipboard_type = 0;
79 const GTypeInfo clipboard_info =
81 sizeof (GtkClipboardClass),
83 NULL, /* base_finalize */
84 (GClassInitFunc) gtk_clipboard_class_init,
85 NULL, /* class_finalize */
86 NULL, /* class_data */
87 sizeof (GtkClipboard),
89 (GInstanceInitFunc) NULL,
92 clipboard_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkClipboard"),
96 return clipboard_type;
100 gtk_clipboard_class_init (GtkClipboardClass *class)
102 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
104 parent_class = g_type_class_peek_parent (class);
106 gobject_class->finalize = gtk_clipboard_finalize;
108 class->owner_change = gtk_clipboard_owner_change;
110 clipboard_signals[OWNER_CHANGE] =
111 g_signal_new (I_("owner-change"),
112 G_TYPE_FROM_CLASS (gobject_class),
114 G_STRUCT_OFFSET (GtkClipboardClass, owner_change),
116 _gtk_marshal_VOID__BOXED,
118 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
122 gtk_clipboard_finalize (GObject *object)
124 G_OBJECT_CLASS (parent_class)->finalize (object);
128 clipboard_display_closed (GdkDisplay *display,
130 GtkClipboard *clipboard)
134 clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
135 g_object_run_dispose (G_OBJECT (clipboard));
136 clipboards = g_slist_remove (clipboards, clipboard);
137 g_object_set_data (G_OBJECT (display), I_("gtk-clipboard-list"), clipboards);
138 g_object_unref (clipboard);
141 static GtkClipboard *
142 clipboard_peek (GdkDisplay *display,
144 gboolean only_if_exists)
146 GtkClipboard *clipboard = NULL;
150 if (selection == GDK_NONE)
151 selection = GDK_SELECTION_CLIPBOARD;
153 clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
155 tmp_list = clipboards;
158 clipboard = tmp_list->data;
159 if (clipboard->selection == selection)
162 tmp_list = tmp_list->next;
165 if (!tmp_list && !only_if_exists)
167 clipboard = g_object_new (GTK_TYPE_CLIPBOARD, NULL);
168 clipboard->selection = selection;
169 clipboard->display = display;
171 clipboards = g_slist_prepend (clipboards, clipboard);
172 g_object_set_data (G_OBJECT (display), I_("gtk-clipboard-list"), clipboards);
173 g_signal_connect (display, "closed",
174 G_CALLBACK (clipboard_display_closed), clipboard);
175 gdk_display_request_selection_notification (display, selection);
182 gtk_clipboard_get_for_display (GdkDisplay *display,
185 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
186 g_return_val_if_fail (!gdk_display_is_closed (display), NULL);
188 return clipboard_peek (display, selection, FALSE);
192 gtk_clipboard_get (GdkAtom selection)
194 return gtk_clipboard_get_for_display (gdk_display_get_default (), selection);
198 struct _SetContentClosure {
199 GtkClipboard *clipboard;
200 GtkClipboardGetFunc get_func;
201 GtkClipboardClearFunc clear_func;
205 GtkTargetPair *targets;
210 _offer_cb (GdkDevice *device,
211 const gchar *mime_type,
215 SetContentClosure *closure = (SetContentClosure *)userdata;
216 GtkSelectionData selection_data = { 0, };
220 selection_data.target = gdk_atom_intern (mime_type, FALSE);
222 for (i = 0; i < closure->n_targets; i++)
224 if (closure->targets[i].target == selection_data.target)
226 info = closure->targets[i].info;
231 closure->get_func (closure->clipboard,
236 *len = gtk_selection_data_get_length (&selection_data);
238 /* The caller of this callback will free this data - the GtkClipboardGetFunc
239 * uses gtk_selection_data_set which copies*/
240 return (gchar *)selection_data.data;
244 clipboard_owner_destroyed (gpointer data,
247 GtkClipboard *clipboard = (GtkClipboard *) data;
248 SetContentClosure *last_closure = clipboard->last_closure;
250 last_closure->userdata = NULL;
251 last_closure->get_func = NULL;
252 last_closure->clear_func = NULL;
253 last_closure->have_owner = FALSE;
255 gtk_clipboard_clear (clipboard);
259 gtk_clipboard_set_contents (GtkClipboard *clipboard,
260 const GtkTargetEntry *targets,
262 GtkClipboardGetFunc get_func,
263 GtkClipboardClearFunc clear_func,
267 GdkDeviceManager *device_manager;
271 SetContentClosure *closure, *last_closure;
273 last_closure = clipboard->last_closure;
275 (!last_closure->have_owner && have_owner) ||
276 (last_closure->userdata != user_data)) {
277 gtk_clipboard_clear (clipboard);
279 closure = g_new0 (SetContentClosure, 1);
280 closure->clipboard = clipboard;
281 closure->userdata = user_data;
282 closure->have_owner = have_owner;
285 g_object_weak_ref (G_OBJECT (user_data), clipboard_owner_destroyed, clipboard);
287 closure = last_closure;
288 g_free (closure->targets);
291 closure->get_func = get_func;
292 closure->clear_func = clear_func;
293 closure->targets = g_new0 (GtkTargetPair, n_targets);
294 closure->n_targets = n_targets;
296 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
297 device = gdk_device_manager_get_client_pointer (device_manager);
299 mimetypes = g_new (gchar *, n_targets);
301 for (i = 0; i < n_targets; i++)
303 mimetypes[i] = targets[i].target;
304 closure->targets[i].target = gdk_atom_intern (targets[i].target, FALSE);
305 closure->targets[i].flags = targets[i].flags;
306 closure->targets[i].info = targets[i].info;
309 gdk_wayland_device_offer_selection_content (device,
310 (const gchar **)mimetypes,
314 clipboard->last_closure = closure;
321 gtk_clipboard_set_with_data (GtkClipboard *clipboard,
322 const GtkTargetEntry *targets,
324 GtkClipboardGetFunc get_func,
325 GtkClipboardClearFunc clear_func,
328 g_return_val_if_fail (clipboard != NULL, FALSE);
329 g_return_val_if_fail (targets != NULL, FALSE);
330 g_return_val_if_fail (get_func != NULL, FALSE);
332 return gtk_clipboard_set_contents (clipboard, targets, n_targets,
333 get_func, clear_func, user_data,
338 gtk_clipboard_set_with_owner (GtkClipboard *clipboard,
339 const GtkTargetEntry *targets,
341 GtkClipboardGetFunc get_func,
342 GtkClipboardClearFunc clear_func,
345 g_return_val_if_fail (clipboard != NULL, FALSE);
346 g_return_val_if_fail (targets != NULL, FALSE);
347 g_return_val_if_fail (get_func != NULL, FALSE);
348 g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
350 return gtk_clipboard_set_contents (clipboard, targets, n_targets,
351 get_func, clear_func, owner,
356 gtk_clipboard_get_owner (GtkClipboard *clipboard)
358 g_return_val_if_fail (clipboard != NULL, NULL);
360 if (clipboard->owner)
361 return clipboard->owner;
367 gtk_clipboard_clear (GtkClipboard *clipboard)
369 GdkDeviceManager *device_manager;
372 if (!clipboard->last_closure)
375 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
376 device = gdk_device_manager_get_client_pointer (device_manager);
378 gdk_wayland_device_clear_selection_content (device);
380 if (clipboard->last_closure->clear_func)
382 clipboard->last_closure->clear_func (clipboard,
383 clipboard->last_closure->userdata);
386 if (clipboard->last_closure->have_owner)
387 g_object_weak_unref (G_OBJECT (clipboard->last_closure->userdata),
388 clipboard_owner_destroyed, clipboard);
389 g_free (clipboard->last_closure->targets);
390 g_free (clipboard->last_closure);
392 clipboard->last_closure = NULL;
396 text_get_func (GtkClipboard *clipboard,
397 GtkSelectionData *selection_data,
401 gtk_selection_data_set_text (selection_data, data, -1);
405 text_clear_func (GtkClipboard *clipboard,
412 gtk_clipboard_set_text (GtkClipboard *clipboard,
416 GtkTargetEntry target = { "text/plain;charset=utf-8", 0, 0 };
418 g_return_if_fail (clipboard != NULL);
419 g_return_if_fail (text != NULL);
424 gtk_clipboard_set_with_data (clipboard,
426 text_get_func, text_clear_func,
427 g_strndup (text, len));
428 gtk_clipboard_set_can_store (clipboard, NULL, 0);
433 pixbuf_get_func (GtkClipboard *clipboard,
434 GtkSelectionData *selection_data,
438 gtk_selection_data_set_pixbuf (selection_data, data);
442 pixbuf_clear_func (GtkClipboard *clipboard,
445 g_object_unref (data);
449 gtk_clipboard_set_image (GtkClipboard *clipboard,
454 GtkTargetEntry *targets;
457 g_return_if_fail (clipboard != NULL);
458 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
460 list = gtk_target_list_new (NULL, 0);
461 gtk_target_list_add_image_targets (list, 0, TRUE);
463 n_targets = g_list_length (list->list);
464 targets = g_new0 (GtkTargetEntry, n_targets);
465 for (l = list->list, i = 0; l; l = l->next, i++)
467 GtkTargetPair *pair = (GtkTargetPair *)l->data;
468 targets[i].target = gdk_atom_name (pair->target);
471 gtk_clipboard_set_with_data (clipboard,
473 pixbuf_get_func, pixbuf_clear_func,
474 g_object_ref (pixbuf));
475 gtk_clipboard_set_can_store (clipboard, NULL, 0);
477 for (i = 0; i < n_targets; i++)
478 g_free (targets[i].target);
480 gtk_target_list_unref (list);
484 GtkClipboard *clipboard;
488 } ClipboardRequestClosure;
491 _request_generic_cb (GdkDevice *device,
496 ClipboardRequestClosure *closure = (ClipboardRequestClosure *)userdata;
497 GtkClipboardReceivedFunc cb = (GtkClipboardReceivedFunc)closure->cb;
498 GtkSelectionData selection_data;
500 selection_data.selection = GDK_SELECTION_CLIPBOARD;
501 selection_data.target = closure->target;
502 selection_data.length = len;
503 selection_data.data = (guchar *)data;
505 cb (closure->clipboard, &selection_data, closure->userdata);
511 gtk_clipboard_request_contents (GtkClipboard *clipboard,
513 GtkClipboardReceivedFunc callback,
516 GdkDeviceManager *device_manager;
518 ClipboardRequestClosure *closure;
520 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
521 device = gdk_device_manager_get_client_pointer (device_manager);
523 closure = g_new0 (ClipboardRequestClosure, 1);
524 closure->clipboard = clipboard;
525 closure->cb = (GCallback)callback;
526 closure->userdata = user_data;
527 closure->target = target;
529 /* TODO: Do we need to check that target is valid ? */
530 gdk_wayland_device_request_selection_content (device,
531 gdk_atom_name (target),
537 _request_text_cb (GdkDevice *device,
542 ClipboardRequestClosure *closure = (ClipboardRequestClosure *)userdata;
543 GtkClipboardTextReceivedFunc cb = (GtkClipboardTextReceivedFunc)closure->cb;
545 cb (closure->clipboard, data, closure->userdata);
551 gtk_clipboard_request_text (GtkClipboard *clipboard,
552 GtkClipboardTextReceivedFunc callback,
555 GdkDeviceManager *device_manager;
558 ClipboardRequestClosure *closure;
560 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
561 device = gdk_device_manager_get_client_pointer (device_manager);
563 closure = g_new0 (ClipboardRequestClosure, 1);
564 closure->clipboard = clipboard;
565 closure->cb = (GCallback)callback;
566 closure->userdata = user_data;
567 gdk_wayland_device_request_selection_content (device,
568 "text/plain;charset=utf-8",
574 gtk_clipboard_request_rich_text (GtkClipboard *clipboard,
575 GtkTextBuffer *buffer,
576 GtkClipboardRichTextReceivedFunc callback,
579 /* FIXME: Implement */
583 gtk_clipboard_request_image (GtkClipboard *clipboard,
584 GtkClipboardImageReceivedFunc callback,
587 /* FIXME: Implement */
591 gtk_clipboard_request_uris (GtkClipboard *clipboard,
592 GtkClipboardURIReceivedFunc callback,
595 /* FIXME: Implement */
599 gtk_clipboard_request_targets (GtkClipboard *clipboard,
600 GtkClipboardTargetsReceivedFunc callback,
606 gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets);
608 callback (clipboard, targets, n_targets, user_data);
615 GtkSelectionData *selection_data;
619 _wait_for_contents_cb (GtkClipboard *clipboard,
620 GtkSelectionData *selection_data,
623 WaitClosure *closure = (WaitClosure *)userdata;
625 if (gtk_selection_data_get_length (selection_data) != -1)
626 closure->selection_data = gtk_selection_data_copy (selection_data);
628 g_main_loop_quit (closure->loop);
632 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
635 GdkDeviceManager *device_manager;
637 WaitClosure *closure;
638 GtkSelectionData *selection_data = NULL;
640 g_return_val_if_fail (clipboard != NULL, NULL);
641 g_return_val_if_fail (target != GDK_NONE, NULL);
643 device_manager = gdk_display_get_device_manager (clipboard->display);
644 device = gdk_device_manager_get_client_pointer (device_manager);
646 if (target == gdk_atom_intern_static_string ("TARGETS"))
651 selection_data = g_slice_new0 (GtkSelectionData);
652 selection_data->selection = GDK_SELECTION_CLIPBOARD;
653 selection_data->target = target;
655 nr_atoms = gdk_wayland_device_get_selection_type_atoms (device, &atoms);
656 gtk_selection_data_set (selection_data,
657 GDK_SELECTION_TYPE_ATOM, 32,
663 return selection_data;
666 closure = g_new0 (WaitClosure, 1);
667 closure->selection_data = NULL;
668 closure->loop = g_main_loop_new (NULL, TRUE);
670 gtk_clipboard_request_contents (clipboard,
672 _wait_for_contents_cb,
675 if (g_main_loop_is_running (closure->loop))
677 gdk_threads_leave ();
678 g_main_loop_run (closure->loop);
679 gdk_threads_enter ();
682 g_main_loop_unref (closure->loop);
684 selection_data = closure->selection_data;
688 return selection_data;
692 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
694 GtkSelectionData *data;
698 gtk_clipboard_wait_for_contents (clipboard,
699 gdk_atom_intern_static_string ("text/plain;charset=utf-8"));
701 result = (gchar *)gtk_selection_data_get_text (data);
703 gtk_selection_data_free (data);
709 gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
711 const gchar *priority[] = { "image/png",
717 GtkSelectionData *data;
719 for (i = 0; i < G_N_ELEMENTS (priority); i++)
721 data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string (priority[i]));
725 GdkPixbuf *pixbuf = gtk_selection_data_get_pixbuf (data);
727 gtk_selection_data_free (data);
737 gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard,
738 GtkTextBuffer *buffer,
742 /* FIXME: Implement */
747 gtk_clipboard_wait_for_uris (GtkClipboard *clipboard)
749 GtkSelectionData *data;
752 gtk_clipboard_wait_for_contents (clipboard,
753 gdk_atom_intern_static_string ("text/uri-list"));
758 uris = gtk_selection_data_get_uris (data);
759 gtk_selection_data_free (data);
768 gtk_clipboard_get_display (GtkClipboard *clipboard)
770 g_return_val_if_fail (clipboard != NULL, NULL);
772 return clipboard->display;
776 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
778 GtkSelectionData *data;
779 gboolean result = FALSE;
782 gtk_clipboard_wait_for_contents (clipboard,
783 gdk_atom_intern_static_string ("TARGETS"));
786 result = gtk_selection_data_targets_include_text (data);
787 gtk_selection_data_free (data);
794 gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard,
795 GtkTextBuffer *buffer)
797 GtkSelectionData *data;
798 gboolean result = FALSE;
800 g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
801 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
804 gtk_clipboard_wait_for_contents (clipboard,
805 gdk_atom_intern_static_string ("TARGETS"));
808 result = gtk_selection_data_targets_include_rich_text (data, buffer);
809 gtk_selection_data_free (data);
816 gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
818 GtkSelectionData *data;
819 gboolean result = FALSE;
822 gtk_clipboard_wait_for_contents (clipboard,
823 gdk_atom_intern_static_string ("TARGETS"));
826 result = gtk_selection_data_targets_include_image (data, FALSE);
827 gtk_selection_data_free (data);
834 gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard)
836 GtkSelectionData *data;
837 gboolean result = FALSE;
840 gtk_clipboard_wait_for_contents (clipboard,
841 gdk_atom_intern_static_string ("TARGETS"));
844 result = gtk_selection_data_targets_include_uri (data);
845 gtk_selection_data_free (data);
852 gtk_clipboard_wait_for_targets (GtkClipboard *clipboard,
856 GtkSelectionData *data;
857 gboolean result = FALSE;
859 g_return_val_if_fail (clipboard != NULL, FALSE);
862 gtk_clipboard_wait_for_contents (clipboard,
863 gdk_atom_intern_static_string ("TARGETS"));
867 GdkAtom *tmp_targets;
870 result = gtk_selection_data_get_targets (data,
875 *n_targets = tmp_n_targets;
878 *targets = tmp_targets;
880 g_free (tmp_targets);
882 gtk_selection_data_free (data);
889 gtk_clipboard_owner_change (GtkClipboard *clipboard,
890 GdkEventOwnerChange *event)
896 gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
901 gboolean retval = FALSE;
903 g_return_val_if_fail (clipboard != NULL, FALSE);
905 if (!gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets))
908 for (i = 0; i < n_targets; i++)
910 if (targets[i] == target)
923 _gtk_clipboard_handle_event (GdkEventOwnerChange *event)
928 gtk_clipboard_set_can_store (GtkClipboard *clipboard,
929 const GtkTargetEntry *targets,
932 /* FIXME: Implement */
936 gtk_clipboard_store (GtkClipboard *clipboard)
938 /* FIXME: Implement */
942 _gtk_clipboard_store_all (void)
944 /* FIXME: Implement */