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;
51 SetContentClosure *last_closure;
54 struct _GtkClipboardClass
56 GObjectClass parent_class;
58 void (*owner_change) (GtkClipboard *clipboard,
59 GdkEventOwnerChange *event);
62 static void gtk_clipboard_class_init (GtkClipboardClass *class);
63 static void gtk_clipboard_finalize (GObject *object);
64 static void gtk_clipboard_owner_change (GtkClipboard *clipboard,
65 GdkEventOwnerChange *event);
67 static GObjectClass *parent_class;
68 static guint clipboard_signals[LAST_SIGNAL] = { 0 };
71 gtk_clipboard_get_type (void)
73 static GType clipboard_type = 0;
77 const GTypeInfo clipboard_info =
79 sizeof (GtkClipboardClass),
81 NULL, /* base_finalize */
82 (GClassInitFunc) gtk_clipboard_class_init,
83 NULL, /* class_finalize */
84 NULL, /* class_data */
85 sizeof (GtkClipboard),
87 (GInstanceInitFunc) NULL,
90 clipboard_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkClipboard"),
94 return clipboard_type;
98 gtk_clipboard_class_init (GtkClipboardClass *class)
100 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
102 parent_class = g_type_class_peek_parent (class);
104 gobject_class->finalize = gtk_clipboard_finalize;
106 class->owner_change = gtk_clipboard_owner_change;
108 clipboard_signals[OWNER_CHANGE] =
109 g_signal_new (I_("owner-change"),
110 G_TYPE_FROM_CLASS (gobject_class),
112 G_STRUCT_OFFSET (GtkClipboardClass, owner_change),
114 _gtk_marshal_VOID__BOXED,
116 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
120 gtk_clipboard_finalize (GObject *object)
122 G_OBJECT_CLASS (parent_class)->finalize (object);
126 gtk_clipboard_get_for_display (GdkDisplay *display,
129 GtkClipboard *clipboard;
131 if (selection == GDK_NONE)
132 selection = GDK_SELECTION_CLIPBOARD;
134 if (selection != GDK_SELECTION_CLIPBOARD)
136 g_warning (G_STRLOC ": Only able to create clipboard for CLIPBOARD");
139 selection = GDK_SELECTION_CLIPBOARD;
141 clipboard = g_object_get_data (G_OBJECT (display), "gtk-clipboard");
146 clipboard = g_object_new (GTK_TYPE_CLIPBOARD, NULL);
147 clipboard->display = display;
149 g_object_set_data (G_OBJECT (display), "gtk-clipboard", clipboard);
151 /* TODO: Need to connect to display closed to free this */
156 gtk_clipboard_get (GdkAtom selection)
158 return gtk_clipboard_get_for_display (gdk_display_get_default (), selection);
162 struct _SetContentClosure {
163 GtkClipboard *clipboard;
164 GtkClipboardGetFunc get_func;
165 GtkClipboardClearFunc clear_func;
168 GtkTargetPair *targets;
173 _offer_cb (GdkDevice *device,
174 const gchar *mime_type,
178 SetContentClosure *closure = (SetContentClosure *)userdata;
179 GtkSelectionData selection_data = { 0, };
183 selection_data.target = gdk_atom_intern (mime_type, FALSE);
185 for (i = 0; i < closure->n_targets; i++)
187 if (closure->targets[i].target == selection_data.target)
189 info = closure->targets[i].info;
194 closure->get_func (closure->clipboard,
199 *len = gtk_selection_data_get_length (&selection_data);
201 /* The caller of this callback will free this data - the GtkClipboardGetFunc
202 * uses gtk_selection_data_set which copies*/
203 return (gchar *)selection_data.data;
207 gtk_clipboard_set_contents (GtkClipboard *clipboard,
208 const GtkTargetEntry *targets,
210 GtkClipboardGetFunc get_func,
211 GtkClipboardClearFunc clear_func,
215 GdkDeviceManager *device_manager;
219 SetContentClosure *closure;
221 gtk_clipboard_clear (clipboard);
223 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
224 device = gdk_device_manager_get_client_pointer (device_manager);
226 closure = g_new0 (SetContentClosure, 1);
227 closure->clipboard = clipboard;
228 closure->get_func = get_func;
229 closure->clear_func = clear_func;
230 closure->userdata = user_data;
231 closure->targets = g_new0 (GtkTargetPair, n_targets);
232 closure->n_targets = n_targets;
234 mimetypes = g_new (gchar *, n_targets);
236 for (i = 0; i < n_targets; i++)
238 mimetypes[i] = targets[i].target;
239 closure->targets[i].target = gdk_atom_intern (targets[i].target, FALSE);
240 closure->targets[i].flags = targets[i].flags;
241 closure->targets[i].info = targets[i].info;
244 gdk_wayland_device_offer_selection_content (device,
245 (const gchar **)mimetypes,
249 clipboard->last_closure = closure;
256 gtk_clipboard_set_with_data (GtkClipboard *clipboard,
257 const GtkTargetEntry *targets,
259 GtkClipboardGetFunc get_func,
260 GtkClipboardClearFunc clear_func,
263 g_return_val_if_fail (clipboard != NULL, FALSE);
264 g_return_val_if_fail (targets != NULL, FALSE);
265 g_return_val_if_fail (get_func != NULL, FALSE);
267 return gtk_clipboard_set_contents (clipboard, targets, n_targets,
268 get_func, clear_func, user_data,
273 gtk_clipboard_set_with_owner (GtkClipboard *clipboard,
274 const GtkTargetEntry *targets,
276 GtkClipboardGetFunc get_func,
277 GtkClipboardClearFunc clear_func,
280 g_return_val_if_fail (clipboard != NULL, FALSE);
281 g_return_val_if_fail (targets != NULL, FALSE);
282 g_return_val_if_fail (get_func != NULL, FALSE);
283 g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
285 return gtk_clipboard_set_contents (clipboard, targets, n_targets,
286 get_func, clear_func, owner,
291 gtk_clipboard_get_owner (GtkClipboard *clipboard)
293 g_return_val_if_fail (clipboard != NULL, NULL);
295 if (clipboard->owner)
296 return clipboard->owner;
302 gtk_clipboard_clear (GtkClipboard *clipboard)
304 GdkDeviceManager *device_manager;
307 if (!clipboard->last_closure)
310 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
311 device = gdk_device_manager_get_client_pointer (device_manager);
313 gdk_wayland_device_clear_selection_content (device);
315 if (clipboard->last_closure->clear_func)
317 clipboard->last_closure->clear_func (clipboard,
318 clipboard->last_closure->userdata);
321 /* TODO: Free last closure */
322 clipboard->last_closure = NULL;
326 text_get_func (GtkClipboard *clipboard,
327 GtkSelectionData *selection_data,
331 gtk_selection_data_set_text (selection_data, data, -1);
335 text_clear_func (GtkClipboard *clipboard,
342 gtk_clipboard_set_text (GtkClipboard *clipboard,
346 GtkTargetEntry target = { "text/plain;charset=utf-8", 0, 0 };
348 g_return_if_fail (clipboard != NULL);
349 g_return_if_fail (text != NULL);
354 gtk_clipboard_set_with_data (clipboard,
356 text_get_func, text_clear_func,
357 g_strndup (text, len));
358 gtk_clipboard_set_can_store (clipboard, NULL, 0);
363 pixbuf_get_func (GtkClipboard *clipboard,
364 GtkSelectionData *selection_data,
368 gtk_selection_data_set_pixbuf (selection_data, data);
372 pixbuf_clear_func (GtkClipboard *clipboard,
375 g_object_unref (data);
379 gtk_clipboard_set_image (GtkClipboard *clipboard,
384 GtkTargetEntry *targets;
387 g_return_if_fail (clipboard != NULL);
388 g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
390 list = gtk_target_list_new (NULL, 0);
391 gtk_target_list_add_image_targets (list, 0, TRUE);
393 n_targets = g_list_length (list->list);
394 targets = g_new0 (GtkTargetEntry, n_targets);
395 for (l = list->list, i = 0; l; l = l->next, i++)
397 GtkTargetPair *pair = (GtkTargetPair *)l->data;
398 targets[i].target = gdk_atom_name (pair->target);
401 gtk_clipboard_set_with_data (clipboard,
403 pixbuf_get_func, pixbuf_clear_func,
404 g_object_ref (pixbuf));
405 gtk_clipboard_set_can_store (clipboard, NULL, 0);
407 for (i = 0; i < n_targets; i++)
408 g_free (targets[i].target);
410 gtk_target_list_unref (list);
414 GtkClipboard *clipboard;
418 } ClipboardRequestClosure;
421 _request_generic_cb (GdkDevice *device,
426 ClipboardRequestClosure *closure = (ClipboardRequestClosure *)userdata;
427 GtkClipboardReceivedFunc cb = (GtkClipboardReceivedFunc)closure->cb;
428 GtkSelectionData selection_data;
430 selection_data.selection = GDK_SELECTION_CLIPBOARD;
431 selection_data.target = closure->target;
432 selection_data.length = len;
433 selection_data.data = (guchar *)data;
435 cb (closure->clipboard, &selection_data, closure->userdata);
441 gtk_clipboard_request_contents (GtkClipboard *clipboard,
443 GtkClipboardReceivedFunc callback,
446 GdkDeviceManager *device_manager;
448 ClipboardRequestClosure *closure;
450 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
451 device = gdk_device_manager_get_client_pointer (device_manager);
453 closure = g_new0 (ClipboardRequestClosure, 1);
454 closure->clipboard = clipboard;
455 closure->cb = (GCallback)callback;
456 closure->userdata = user_data;
457 closure->target = target;
459 /* TODO: Do we need to check that target is valid ? */
460 gdk_wayland_device_request_selection_content (device,
461 gdk_atom_name (target),
467 _request_text_cb (GdkDevice *device,
472 ClipboardRequestClosure *closure = (ClipboardRequestClosure *)userdata;
473 GtkClipboardTextReceivedFunc cb = (GtkClipboardTextReceivedFunc)closure->cb;
475 cb (closure->clipboard, data, closure->userdata);
481 gtk_clipboard_request_text (GtkClipboard *clipboard,
482 GtkClipboardTextReceivedFunc callback,
485 GdkDeviceManager *device_manager;
488 ClipboardRequestClosure *closure;
490 device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
491 device = gdk_device_manager_get_client_pointer (device_manager);
493 closure = g_new0 (ClipboardRequestClosure, 1);
494 closure->clipboard = clipboard;
495 closure->cb = (GCallback)callback;
496 closure->userdata = user_data;
497 gdk_wayland_device_request_selection_content (device,
498 "text/plain;charset=utf-8",
504 gtk_clipboard_request_rich_text (GtkClipboard *clipboard,
505 GtkTextBuffer *buffer,
506 GtkClipboardRichTextReceivedFunc callback,
509 /* FIXME: Implement */
513 gtk_clipboard_request_image (GtkClipboard *clipboard,
514 GtkClipboardImageReceivedFunc callback,
517 /* FIXME: Implement */
521 gtk_clipboard_request_uris (GtkClipboard *clipboard,
522 GtkClipboardURIReceivedFunc callback,
525 /* FIXME: Implement */
529 gtk_clipboard_request_targets (GtkClipboard *clipboard,
530 GtkClipboardTargetsReceivedFunc callback,
536 gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets);
538 callback (clipboard, targets, n_targets, user_data);
545 GtkSelectionData *selection_data;
549 _wait_for_contents_cb (GtkClipboard *clipboard,
550 GtkSelectionData *selection_data,
553 WaitClosure *closure = (WaitClosure *)userdata;
555 if (gtk_selection_data_get_length (selection_data) != -1)
556 closure->selection_data = gtk_selection_data_copy (selection_data);
558 g_main_loop_quit (closure->loop);
562 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
565 GdkDeviceManager *device_manager;
567 WaitClosure *closure;
568 GtkSelectionData *selection_data = NULL;
570 g_return_val_if_fail (clipboard != NULL, NULL);
571 g_return_val_if_fail (target != GDK_NONE, NULL);
573 device_manager = gdk_display_get_device_manager (clipboard->display);
574 device = gdk_device_manager_get_client_pointer (device_manager);
576 if (target == gdk_atom_intern_static_string ("TARGETS"))
581 selection_data = g_slice_new0 (GtkSelectionData);
582 selection_data->selection = GDK_SELECTION_CLIPBOARD;
583 selection_data->target = target;
585 nr_atoms = gdk_wayland_device_get_selection_type_atoms (device, &atoms);
586 gtk_selection_data_set (selection_data,
587 GDK_SELECTION_TYPE_ATOM, 32,
593 return selection_data;
596 closure = g_new0 (WaitClosure, 1);
597 closure->selection_data = NULL;
598 closure->loop = g_main_loop_new (NULL, TRUE);
600 gtk_clipboard_request_contents (clipboard,
602 _wait_for_contents_cb,
605 if (g_main_loop_is_running (closure->loop))
607 GDK_THREADS_LEAVE ();
608 g_main_loop_run (closure->loop);
609 GDK_THREADS_ENTER ();
612 g_main_loop_unref (closure->loop);
614 selection_data = closure->selection_data;
618 return selection_data;
622 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
624 GtkSelectionData *data;
628 gtk_clipboard_wait_for_contents (clipboard,
629 gdk_atom_intern_static_string ("text/plain;charset=utf-8"));
631 result = (gchar *)gtk_selection_data_get_text (data);
633 gtk_selection_data_free (data);
639 gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
641 const gchar *priority[] = { "image/png",
647 GtkSelectionData *data;
649 for (i = 0; i < G_N_ELEMENTS (priority); i++)
651 data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string (priority[i]));
655 GdkPixbuf *pixbuf = gtk_selection_data_get_pixbuf (data);
657 gtk_selection_data_free (data);
667 gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard,
668 GtkTextBuffer *buffer,
672 /* FIXME: Implement */
677 gtk_clipboard_wait_for_uris (GtkClipboard *clipboard)
679 GtkSelectionData *data;
682 gtk_clipboard_wait_for_contents (clipboard,
683 gdk_atom_intern_static_string ("text/uri-list"));
688 uris = gtk_selection_data_get_uris (data);
689 gtk_selection_data_free (data);
698 gtk_clipboard_get_display (GtkClipboard *clipboard)
700 g_return_val_if_fail (clipboard != NULL, NULL);
702 return clipboard->display;
706 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
708 GtkSelectionData *data;
709 gboolean result = FALSE;
712 gtk_clipboard_wait_for_contents (clipboard,
713 gdk_atom_intern_static_string ("TARGETS"));
716 result = gtk_selection_data_targets_include_text (data);
717 gtk_selection_data_free (data);
724 gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard,
725 GtkTextBuffer *buffer)
727 GtkSelectionData *data;
728 gboolean result = FALSE;
730 g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
731 g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
734 gtk_clipboard_wait_for_contents (clipboard,
735 gdk_atom_intern_static_string ("TARGETS"));
738 result = gtk_selection_data_targets_include_rich_text (data, buffer);
739 gtk_selection_data_free (data);
746 gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
748 GtkSelectionData *data;
749 gboolean result = FALSE;
752 gtk_clipboard_wait_for_contents (clipboard,
753 gdk_atom_intern_static_string ("TARGETS"));
756 result = gtk_selection_data_targets_include_image (data, FALSE);
757 gtk_selection_data_free (data);
764 gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard)
766 GtkSelectionData *data;
767 gboolean result = FALSE;
770 gtk_clipboard_wait_for_contents (clipboard,
771 gdk_atom_intern_static_string ("TARGETS"));
774 result = gtk_selection_data_targets_include_uri (data);
775 gtk_selection_data_free (data);
782 gtk_clipboard_wait_for_targets (GtkClipboard *clipboard,
786 GtkSelectionData *data;
787 gboolean result = FALSE;
789 g_return_val_if_fail (clipboard != NULL, FALSE);
792 gtk_clipboard_wait_for_contents (clipboard,
793 gdk_atom_intern_static_string ("TARGETS"));
797 GdkAtom *tmp_targets;
800 result = gtk_selection_data_get_targets (data,
805 *n_targets = tmp_n_targets;
808 *targets = tmp_targets;
810 g_free (tmp_targets);
812 gtk_selection_data_free (data);
819 gtk_clipboard_owner_change (GtkClipboard *clipboard,
820 GdkEventOwnerChange *event)
826 gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
831 gboolean retval = FALSE;
833 g_return_val_if_fail (clipboard != NULL, FALSE);
835 if (!gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets))
838 for (i = 0; i < n_targets; i++)
840 if (targets[i] == target)
853 _gtk_clipboard_handle_event (GdkEventOwnerChange *event)
858 gtk_clipboard_set_can_store (GtkClipboard *clipboard,
859 const GtkTargetEntry *targets,
862 /* FIXME: Implement */
866 gtk_clipboard_store (GtkClipboard *clipboard)
868 /* FIXME: Implement */
872 _gtk_clipboard_store_all (void)
874 /* FIXME: Implement */