]> Pileus Git - ~andy/gtk/blob - gtk/gtkclipboard-quartz.c
quartz: fix crash in the recent clipboard "fix", and really fix it
[~andy/gtk] / gtk / gtkclipboard-quartz.c
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  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "config.h"
22 #include <string.h>
23
24 #import <Cocoa/Cocoa.h>
25
26 #include "gtkclipboard.h"
27 #include "gtkinvisible.h"
28 #include "gtkmain.h"
29 #include "gtkmarshalers.h"
30 #include "gtkintl.h"
31 #include "gtktextbuffer.h"
32 #include "gtkselectionprivate.h"
33 #include "gtkquartz.h"
34
35
36 enum {
37   OWNER_CHANGE,
38   LAST_SIGNAL
39 };
40
41 @interface GtkClipboardOwner : NSObject {
42   GtkClipboard *clipboard;
43   gboolean setting_same_owner;
44 }
45
46 @end
47
48 typedef struct _GtkClipboardClass GtkClipboardClass;
49
50 struct _GtkClipboard 
51 {
52   GObject parent_instance;
53
54   NSPasteboard *pasteboard;
55   GtkClipboardOwner *owner;
56   NSInteger change_count;
57
58   GdkAtom selection;
59
60   GtkClipboardGetFunc get_func;
61   GtkClipboardClearFunc clear_func;
62   gpointer user_data;
63   gboolean have_owner;
64   GtkTargetList *target_list;
65
66   gboolean have_selection;
67   GdkDisplay *display;
68
69   GdkAtom *cached_targets;
70   gint     n_cached_targets;
71
72   guint      notify_signal_id;
73   gboolean   storing_selection;
74   GMainLoop *store_loop;
75   guint      store_timeout;
76   gint       n_storable_targets;
77   GdkAtom   *storable_targets;
78 };
79
80 struct _GtkClipboardClass
81 {
82   GObjectClass parent_class;
83
84   void (*owner_change) (GtkClipboard        *clipboard,
85                         GdkEventOwnerChange *event);
86 };
87
88 static void gtk_clipboard_class_init   (GtkClipboardClass   *class);
89 static void gtk_clipboard_finalize     (GObject             *object);
90 static void gtk_clipboard_owner_change (GtkClipboard        *clipboard,
91                                         GdkEventOwnerChange *event);
92
93 static void          clipboard_unset      (GtkClipboard     *clipboard);
94 static GtkClipboard *clipboard_peek       (GdkDisplay       *display,
95                                            GdkAtom           selection,
96                                            gboolean          only_if_exists);
97
98 @implementation GtkClipboardOwner
99 -(void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
100 {
101   GtkSelectionData selection_data;
102   guint info;
103
104   if (!clipboard->target_list)
105     return;
106
107   memset (&selection_data, 0, sizeof (GtkSelectionData));
108
109   selection_data.selection = clipboard->selection;
110   selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type);
111   selection_data.display = gdk_display_get_default ();
112   selection_data.length = -1;
113
114   if (gtk_target_list_find (clipboard->target_list, selection_data.target, &info))
115     {
116       clipboard->get_func (clipboard, &selection_data,
117                            info,
118                            clipboard->user_data);
119
120       if (selection_data.length >= 0)
121         _gtk_quartz_set_selection_data_for_pasteboard (clipboard->pasteboard,
122                                                        &selection_data);
123
124       g_free (selection_data.data);
125     }
126 }
127
128 /*  pasteboardChangedOwner is not called immediately, and it's not called
129  *  reliably. It is somehow documented in the apple api docs, but the docs
130  *  suck and don't really give clear instructions. Therefore we track
131  *  changeCount in several places below and clear the clipboard if it
132  *  changed.
133  */
134 - (void)pasteboardChangedOwner:(NSPasteboard *)sender
135 {
136   if (! setting_same_owner)
137     clipboard_unset (clipboard);
138 }
139
140 - (id)initWithClipboard:(GtkClipboard *)aClipboard
141 {
142   self = [super init];
143
144   if (self) 
145     {
146       clipboard = aClipboard;
147       setting_same_owner = FALSE;
148     }
149
150   return self;
151 }
152
153 @end
154
155
156 static const gchar clipboards_owned_key[] = "gtk-clipboards-owned";
157 static GQuark clipboards_owned_key_id = 0;
158
159 static GObjectClass *parent_class;
160 static guint         clipboard_signals[LAST_SIGNAL] = { 0 };
161
162 GType
163 gtk_clipboard_get_type (void)
164 {
165   static GType clipboard_type = 0;
166   
167   if (!clipboard_type)
168     {
169       const GTypeInfo clipboard_info =
170       {
171         sizeof (GtkClipboardClass),
172         NULL,           /* base_init */
173         NULL,           /* base_finalize */
174         (GClassInitFunc) gtk_clipboard_class_init,
175         NULL,           /* class_finalize */
176         NULL,           /* class_data */
177         sizeof (GtkClipboard),
178         0,              /* n_preallocs */
179         (GInstanceInitFunc) NULL,
180       };
181       
182       clipboard_type = g_type_register_static (G_TYPE_OBJECT, I_("GtkClipboard"),
183                                                &clipboard_info, 0);
184     }
185   
186   return clipboard_type;
187 }
188
189 static void
190 gtk_clipboard_class_init (GtkClipboardClass *class)
191 {
192   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
193
194   parent_class = g_type_class_peek_parent (class);
195   
196   gobject_class->finalize = gtk_clipboard_finalize;
197
198   class->owner_change = gtk_clipboard_owner_change;
199
200   clipboard_signals[OWNER_CHANGE] =
201     g_signal_new (I_("owner-change"),
202                   G_TYPE_FROM_CLASS (gobject_class),
203                   G_SIGNAL_RUN_FIRST,
204                   G_STRUCT_OFFSET (GtkClipboardClass, owner_change),
205                   NULL, NULL,
206                   _gtk_marshal_VOID__BOXED,
207                   G_TYPE_NONE, 1,
208                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
209 }
210
211 static void
212 gtk_clipboard_finalize (GObject *object)
213 {
214   GtkClipboard *clipboard;
215   GSList *clipboards;
216
217   clipboard = GTK_CLIPBOARD (object);
218
219   clipboards = g_object_get_data (G_OBJECT (clipboard->display), "gtk-clipboard-list");
220   if (g_slist_index (clipboards, clipboard) >= 0)
221     g_warning ("GtkClipboard prematurely finalized");
222
223   clipboard_unset (clipboard);
224   
225   clipboards = g_object_get_data (G_OBJECT (clipboard->display), "gtk-clipboard-list");
226   clipboards = g_slist_remove (clipboards, clipboard);
227   g_object_set_data (G_OBJECT (clipboard->display), I_("gtk-clipboard-list"), clipboards);
228
229   if (clipboard->store_loop && g_main_loop_is_running (clipboard->store_loop))
230     g_main_loop_quit (clipboard->store_loop);
231
232   if (clipboard->store_timeout != 0)
233     g_source_remove (clipboard->store_timeout);
234
235   g_free (clipboard->storable_targets);
236
237   G_OBJECT_CLASS (parent_class)->finalize (object);
238 }
239
240 static void
241 clipboard_display_closed (GdkDisplay   *display,
242                           gboolean      is_error,
243                           GtkClipboard *clipboard)
244 {
245   GSList *clipboards;
246
247   clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
248   g_object_run_dispose (G_OBJECT (clipboard));
249   clipboards = g_slist_remove (clipboards, clipboard);
250   g_object_set_data (G_OBJECT (display), I_("gtk-clipboard-list"), clipboards);
251   g_object_unref (clipboard);
252 }
253
254 GtkClipboard *
255 gtk_clipboard_get_for_display (GdkDisplay *display,
256                                GdkAtom     selection)
257 {
258   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
259   g_return_val_if_fail (!gdk_display_is_closed (display), NULL);
260
261   return clipboard_peek (display, selection, FALSE);
262 }
263
264 GtkClipboard *
265 gtk_clipboard_get (GdkAtom selection)
266 {
267   return gtk_clipboard_get_for_display (gdk_display_get_default (), selection);
268 }
269
270 static void
271 clipboard_owner_destroyed (gpointer data)
272 {
273   GSList *clipboards = data;
274   GSList *tmp_list;
275
276   tmp_list = clipboards;
277   while (tmp_list)
278     {
279       GtkClipboard *clipboard = tmp_list->data;
280
281       clipboard->get_func = NULL;
282       clipboard->clear_func = NULL;
283       clipboard->user_data = NULL;
284       clipboard->have_owner = FALSE;
285
286       if (clipboard->target_list)
287         {
288           gtk_target_list_unref (clipboard->target_list);
289           clipboard->target_list = NULL;
290         }
291
292       gtk_clipboard_clear (clipboard);
293
294       tmp_list = tmp_list->next;
295     }
296   
297   g_slist_free (clipboards);
298 }
299
300 static void
301 clipboard_add_owner_notify (GtkClipboard *clipboard)
302 {
303   if (!clipboards_owned_key_id)
304     clipboards_owned_key_id = g_quark_from_static_string (clipboards_owned_key);
305   
306   if (clipboard->have_owner)
307     g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
308                              g_slist_prepend (g_object_steal_qdata (clipboard->user_data,
309                                                                     clipboards_owned_key_id),
310                                               clipboard),
311                              clipboard_owner_destroyed);
312 }
313
314 static void
315 clipboard_remove_owner_notify (GtkClipboard *clipboard)
316 {
317   if (clipboard->have_owner)
318      g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
319                               g_slist_remove (g_object_steal_qdata (clipboard->user_data,
320                                                                     clipboards_owned_key_id),
321                                               clipboard),
322                               clipboard_owner_destroyed);
323 }
324
325 static gboolean
326 gtk_clipboard_set_contents (GtkClipboard         *clipboard,
327                             const GtkTargetEntry *targets,
328                             guint                 n_targets,
329                             GtkClipboardGetFunc   get_func,
330                             GtkClipboardClearFunc clear_func,
331                             gpointer              user_data,
332                             gboolean              have_owner)
333 {
334   GtkClipboardOwner *owner;
335   NSSet *types;
336   NSAutoreleasePool *pool;
337
338   if (!(clipboard->have_owner && have_owner) ||
339       clipboard->user_data != user_data)
340     {
341       clipboard_unset (clipboard);
342
343       if (clipboard->get_func)
344         {
345           /* Calling unset() caused the clipboard contents to be reset!
346            * Avoid leaking and return
347            */
348           if (!(clipboard->have_owner && have_owner) ||
349               clipboard->user_data != user_data)
350             {
351               (*clear_func) (clipboard, user_data);
352               return FALSE;
353             }
354           else
355             {
356               return TRUE;
357             }
358         }
359     }
360
361   pool = [[NSAutoreleasePool alloc] init];
362
363   types = _gtk_quartz_target_entries_to_pasteboard_types (targets, n_targets);
364
365   /*  call declareTypes before setting the clipboard members because
366    *  declareTypes might clear the clipboard
367    */
368   if (user_data && user_data == clipboard->user_data)
369     {
370       owner = [clipboard->owner retain];
371
372       owner->setting_same_owner = TRUE;
373       clipboard->change_count = [clipboard->pasteboard declareTypes: [types allObjects]
374                                                               owner: owner];
375       owner->setting_same_owner = FALSE;
376     }
377   else
378     {
379       owner = [[GtkClipboardOwner alloc] initWithClipboard:clipboard];
380
381       clipboard->change_count = [clipboard->pasteboard declareTypes: [types allObjects]
382                                                               owner: owner];
383     }
384
385   [owner release];
386   [types release];
387   [pool release];
388
389   clipboard->owner = owner;
390   clipboard->user_data = user_data;
391   clipboard->have_owner = have_owner;
392   if (have_owner)
393     clipboard_add_owner_notify (clipboard);
394   clipboard->get_func = get_func;
395   clipboard->clear_func = clear_func;
396
397   if (clipboard->target_list)
398     gtk_target_list_unref (clipboard->target_list);
399   clipboard->target_list = gtk_target_list_new (targets, n_targets);
400
401   return TRUE;
402 }
403
404 gboolean
405 gtk_clipboard_set_with_data (GtkClipboard          *clipboard,
406                              const GtkTargetEntry  *targets,
407                              guint                  n_targets,
408                              GtkClipboardGetFunc    get_func,
409                              GtkClipboardClearFunc  clear_func,
410                              gpointer               user_data)
411 {
412   g_return_val_if_fail (clipboard != NULL, FALSE);
413   g_return_val_if_fail (targets != NULL, FALSE);
414   g_return_val_if_fail (get_func != NULL, FALSE);
415
416   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
417                                      get_func, clear_func, user_data,
418                                      FALSE);
419 }
420
421 gboolean
422 gtk_clipboard_set_with_owner (GtkClipboard          *clipboard,
423                               const GtkTargetEntry  *targets,
424                               guint                  n_targets,
425                               GtkClipboardGetFunc    get_func,
426                               GtkClipboardClearFunc  clear_func,
427                               GObject               *owner)
428 {
429   g_return_val_if_fail (clipboard != NULL, FALSE);
430   g_return_val_if_fail (targets != NULL, FALSE);
431   g_return_val_if_fail (get_func != NULL, FALSE);
432   g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
433
434   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
435                                      get_func, clear_func, owner,
436                                      TRUE);
437 }
438
439 GObject *
440 gtk_clipboard_get_owner (GtkClipboard *clipboard)
441 {
442   g_return_val_if_fail (clipboard != NULL, NULL);
443
444   if (clipboard->change_count < [clipboard->pasteboard changeCount])
445     {
446       clipboard_unset (clipboard);
447       clipboard->change_count = [clipboard->pasteboard changeCount];
448     }
449
450   if (clipboard->have_owner)
451     return clipboard->user_data;
452   else
453     return NULL;
454 }
455
456 static void
457 clipboard_unset (GtkClipboard *clipboard)
458 {
459   GtkClipboardClearFunc old_clear_func;
460   gpointer old_data;
461   gboolean old_have_owner;
462   gint old_n_storable_targets;
463   
464   old_clear_func = clipboard->clear_func;
465   old_data = clipboard->user_data;
466   old_have_owner = clipboard->have_owner;
467   old_n_storable_targets = clipboard->n_storable_targets;
468   
469   if (old_have_owner)
470     {
471       clipboard_remove_owner_notify (clipboard);
472       clipboard->have_owner = FALSE;
473     }
474
475   clipboard->n_storable_targets = -1;
476   g_free (clipboard->storable_targets);
477   clipboard->storable_targets = NULL;
478
479   clipboard->owner = NULL;
480   clipboard->get_func = NULL;
481   clipboard->clear_func = NULL;
482   clipboard->user_data = NULL;
483   
484   if (old_clear_func)
485     old_clear_func (clipboard, old_data);
486
487   if (clipboard->target_list)
488     {
489       gtk_target_list_unref (clipboard->target_list);
490       clipboard->target_list = NULL;
491     }
492
493   /* If we've transferred the clipboard data to the manager,
494    * unref the owner
495    */
496   if (old_have_owner &&
497       old_n_storable_targets != -1)
498     g_object_unref (old_data);
499 }
500
501 void
502 gtk_clipboard_clear (GtkClipboard *clipboard)
503 {
504   clipboard_unset (clipboard);
505
506   [clipboard->pasteboard declareTypes:nil owner:nil];
507 }
508
509 static void 
510 text_get_func (GtkClipboard     *clipboard,
511                GtkSelectionData *selection_data,
512                guint             info,
513                gpointer          data)
514 {
515   gtk_selection_data_set_text (selection_data, data, -1);
516 }
517
518 static void 
519 text_clear_func (GtkClipboard *clipboard,
520                  gpointer      data)
521 {
522   g_free (data);
523 }
524
525 void 
526 gtk_clipboard_set_text (GtkClipboard *clipboard,
527                         const gchar  *text,
528                         gint          len)
529 {
530   GtkTargetEntry target = { "UTF8_STRING", 0, 0 };
531
532   g_return_if_fail (clipboard != NULL);
533   g_return_if_fail (text != NULL);
534   
535   if (len < 0)
536     len = strlen (text);
537   
538   gtk_clipboard_set_with_data (clipboard, 
539                                &target, 1,
540                                text_get_func, text_clear_func,
541                                g_strndup (text, len));
542   gtk_clipboard_set_can_store (clipboard, NULL, 0);
543 }
544
545
546 static void 
547 pixbuf_get_func (GtkClipboard     *clipboard,
548                  GtkSelectionData *selection_data,
549                  guint             info,
550                  gpointer          data)
551 {
552   gtk_selection_data_set_pixbuf (selection_data, data);
553 }
554
555 static void 
556 pixbuf_clear_func (GtkClipboard *clipboard,
557                    gpointer      data)
558 {
559   g_object_unref (data);
560 }
561
562 void
563 gtk_clipboard_set_image (GtkClipboard *clipboard,
564                          GdkPixbuf    *pixbuf)
565 {
566   GtkTargetList *list;
567   GList *l;
568   GtkTargetEntry *targets;
569   gint n_targets, i;
570
571   g_return_if_fail (clipboard != NULL);
572   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
573
574   list = gtk_target_list_new (NULL, 0);
575   gtk_target_list_add_image_targets (list, 0, TRUE);
576
577   n_targets = g_list_length (list->list);
578   targets = g_new0 (GtkTargetEntry, n_targets);
579   for (l = list->list, i = 0; l; l = l->next, i++)
580     {
581       GtkTargetPair *pair = (GtkTargetPair *)l->data;
582       targets[i].target = gdk_atom_name (pair->target);
583     }
584
585   gtk_clipboard_set_with_data (clipboard, 
586                                targets, n_targets,
587                                pixbuf_get_func, pixbuf_clear_func,
588                                g_object_ref (pixbuf));
589   gtk_clipboard_set_can_store (clipboard, NULL, 0);
590
591   for (i = 0; i < n_targets; i++)
592     g_free (targets[i].target);
593   g_free (targets);
594   gtk_target_list_unref (list);
595 }
596
597 void 
598 gtk_clipboard_request_contents (GtkClipboard            *clipboard,
599                                 GdkAtom                  target,
600                                 GtkClipboardReceivedFunc callback,
601                                 gpointer                 user_data)
602 {
603   GtkSelectionData *data;
604
605   data = gtk_clipboard_wait_for_contents (clipboard, target);
606
607   callback (clipboard, data, user_data);
608
609   gtk_selection_data_free (data);
610 }
611
612 void 
613 gtk_clipboard_request_text (GtkClipboard                *clipboard,
614                             GtkClipboardTextReceivedFunc callback,
615                             gpointer                     user_data)
616 {
617   gchar *data = gtk_clipboard_wait_for_text (clipboard);
618
619   callback (clipboard, data, user_data);
620
621   g_free (data);
622 }
623
624 void
625 gtk_clipboard_request_rich_text (GtkClipboard                    *clipboard,
626                                  GtkTextBuffer                   *buffer,
627                                  GtkClipboardRichTextReceivedFunc callback,
628                                  gpointer                         user_data)
629 {
630   /* FIXME: Implement */
631 }
632
633
634 guint8 *
635 gtk_clipboard_wait_for_rich_text (GtkClipboard  *clipboard,
636                                   GtkTextBuffer *buffer,
637                                   GdkAtom       *format,
638                                   gsize         *length)
639 {
640   /* FIXME: Implement */
641   return NULL;
642 }
643
644 void 
645 gtk_clipboard_request_image (GtkClipboard                  *clipboard,
646                              GtkClipboardImageReceivedFunc  callback,
647                              gpointer                       user_data)
648 {
649   GdkPixbuf *pixbuf = gtk_clipboard_wait_for_image (clipboard);
650
651   callback (clipboard, pixbuf, user_data);
652
653   if (pixbuf)
654     g_object_unref (pixbuf);
655 }
656
657 void 
658 gtk_clipboard_request_uris (GtkClipboard                *clipboard,
659                             GtkClipboardURIReceivedFunc  callback,
660                             gpointer                     user_data)
661 {
662   gchar **uris = gtk_clipboard_wait_for_uris (clipboard);
663
664   callback (clipboard, uris, user_data);
665
666   g_strfreev (uris);
667 }
668
669 void 
670 gtk_clipboard_request_targets (GtkClipboard                *clipboard,
671                                GtkClipboardTargetsReceivedFunc callback,
672                                gpointer                     user_data)
673 {
674   GdkAtom *targets;
675   gint n_targets;
676
677   gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets);
678
679   callback (clipboard, targets, n_targets, user_data);
680 }
681
682 GtkSelectionData *
683 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
684                                  GdkAtom       target)
685 {
686   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
687   GtkSelectionData *selection_data = NULL;
688
689   if (clipboard->change_count < [clipboard->pasteboard changeCount])
690     {
691       clipboard_unset (clipboard);
692       clipboard->change_count = [clipboard->pasteboard changeCount];
693     }
694
695   if (target == gdk_atom_intern_static_string ("TARGETS")) 
696     {
697       NSArray *types = [clipboard->pasteboard types];
698       int i, length;
699       GList *atom_list, *l;
700       GdkAtom *atoms;
701
702       length = [types count] * sizeof (GdkAtom);
703       
704       selection_data = g_slice_new0 (GtkSelectionData);
705       selection_data->selection = clipboard->selection;
706       selection_data->target = target;
707
708       atoms = g_malloc (length);
709
710       atom_list = _gtk_quartz_pasteboard_types_to_atom_list (types);
711       for (l = atom_list, i = 0; l ; l = l->next, i++)
712         atoms[i] = GDK_POINTER_TO_ATOM (l->data);
713       g_list_free (atom_list);
714
715       gtk_selection_data_set (selection_data,
716                               GDK_SELECTION_TYPE_ATOM, 32,
717                               (guchar *)atoms, length);
718
719       [pool release];
720
721       return selection_data;
722     }
723
724   selection_data = _gtk_quartz_get_selection_data_from_pasteboard (clipboard->pasteboard,
725                                                                    target,
726                                                                    clipboard->selection);
727
728   [pool release];
729
730   return selection_data;
731 }
732
733 gchar *
734 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
735 {
736   GtkSelectionData *data;
737   gchar *result;
738
739   data = gtk_clipboard_wait_for_contents (clipboard, 
740                                           gdk_atom_intern_static_string ("UTF8_STRING"));
741
742   result = (gchar *)gtk_selection_data_get_text (data);
743
744   gtk_selection_data_free (data);
745
746   return result;
747 }
748
749 GdkPixbuf *
750 gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
751 {
752   const gchar *priority[] = { "image/png", "image/tiff", "image/jpeg", "image/gif", "image/bmp" };
753   int i;
754   GtkSelectionData *data;
755
756   for (i = 0; i < G_N_ELEMENTS (priority); i++) 
757     {    
758       data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string (priority[i]));
759
760       if (data)
761         {
762           GdkPixbuf *pixbuf = gtk_selection_data_get_pixbuf (data);
763
764           gtk_selection_data_free (data);
765
766           return pixbuf;
767         }  
768   }
769
770   return NULL;
771 }
772
773 gchar **
774 gtk_clipboard_wait_for_uris (GtkClipboard *clipboard)
775 {
776   GtkSelectionData *data;
777
778   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("text/uri-list"));
779   if (data)
780     {
781       gchar **uris;
782
783       uris = gtk_selection_data_get_uris (data);
784       gtk_selection_data_free (data);
785
786       return uris;
787     }  
788
789   return NULL;
790 }
791
792 GdkDisplay *
793 gtk_clipboard_get_display (GtkClipboard *clipboard)
794 {
795   g_return_val_if_fail (clipboard != NULL, NULL);
796
797   return clipboard->display;
798 }
799
800 gboolean
801 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
802 {
803   GtkSelectionData *data;
804   gboolean result = FALSE;
805
806   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
807   if (data)
808     {
809       result = gtk_selection_data_targets_include_text (data);
810       gtk_selection_data_free (data);
811     }
812
813   return result;
814 }
815
816 gboolean
817 gtk_clipboard_wait_is_rich_text_available (GtkClipboard  *clipboard,
818                                            GtkTextBuffer *buffer)
819 {
820   GtkSelectionData *data;
821   gboolean result = FALSE;
822
823   g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
824   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
825
826   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
827   if (data)
828     {
829       result = gtk_selection_data_targets_include_rich_text (data, buffer);
830       gtk_selection_data_free (data);
831     }
832
833   return result;
834 }
835
836 gboolean
837 gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
838 {
839   GtkSelectionData *data;
840   gboolean result = FALSE;
841
842   data = gtk_clipboard_wait_for_contents (clipboard, 
843                                           gdk_atom_intern_static_string ("TARGETS"));
844   if (data)
845     {
846       result = gtk_selection_data_targets_include_image (data, FALSE);
847       gtk_selection_data_free (data);
848     }
849
850   return result;
851 }
852
853 gboolean
854 gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard)
855 {
856   GtkSelectionData *data;
857   gboolean result = FALSE;
858
859   data = gtk_clipboard_wait_for_contents (clipboard, 
860                                           gdk_atom_intern_static_string ("TARGETS"));
861   if (data)
862     {
863       result = gtk_selection_data_targets_include_uri (data);
864       gtk_selection_data_free (data);
865     }
866
867   return result;
868 }
869
870 gboolean
871 gtk_clipboard_wait_for_targets (GtkClipboard  *clipboard, 
872                                 GdkAtom      **targets,
873                                 gint          *n_targets)
874 {
875   GtkSelectionData *data;
876   gboolean result = FALSE;
877   
878   g_return_val_if_fail (clipboard != NULL, FALSE);
879
880   /* If the display supports change notification we cache targets */
881   if (gdk_display_supports_selection_notification (gtk_clipboard_get_display (clipboard)) &&
882       clipboard->n_cached_targets != -1)
883     {
884       if (n_targets)
885         *n_targets = clipboard->n_cached_targets;
886  
887       if (targets)
888         *targets = g_memdup (clipboard->cached_targets,
889                              clipboard->n_cached_targets * sizeof (GdkAtom));
890
891        return TRUE;
892     }
893   
894   if (n_targets)
895     *n_targets = 0;
896       
897   if (targets)
898     *targets = NULL;      
899
900   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
901
902   if (data)
903     {
904       GdkAtom *tmp_targets;
905       gint tmp_n_targets;
906        
907       result = gtk_selection_data_get_targets (data, &tmp_targets, &tmp_n_targets);
908  
909       if (gdk_display_supports_selection_notification (gtk_clipboard_get_display (clipboard)))
910         {
911           clipboard->n_cached_targets = tmp_n_targets;
912           clipboard->cached_targets = g_memdup (tmp_targets,
913                                                 tmp_n_targets * sizeof (GdkAtom));
914         }
915  
916       if (n_targets)
917         *n_targets = tmp_n_targets;
918  
919       if (targets)
920         *targets = tmp_targets;
921       else
922         g_free (tmp_targets);
923       
924       gtk_selection_data_free (data);
925     }
926
927   return result;
928 }
929
930 static GtkClipboard *
931 clipboard_peek (GdkDisplay *display, 
932                 GdkAtom     selection,
933                 gboolean    only_if_exists)
934 {
935   GtkClipboard *clipboard = NULL;
936   GSList *clipboards;
937   GSList *tmp_list;
938
939   if (selection == GDK_NONE)
940     selection = GDK_SELECTION_CLIPBOARD;
941
942   clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
943
944   tmp_list = clipboards;
945   while (tmp_list)
946     {
947       clipboard = tmp_list->data;
948       if (clipboard->selection == selection)
949         break;
950
951       tmp_list = tmp_list->next;
952     }
953
954   if (!tmp_list && !only_if_exists)
955     {
956       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
957       NSString *pasteboard_name;
958       clipboard = g_object_new (GTK_TYPE_CLIPBOARD, NULL);
959
960       if (selection == GDK_SELECTION_CLIPBOARD) 
961         pasteboard_name = NSGeneralPboard;
962       else 
963         {
964           char *atom_string = gdk_atom_name (selection);
965
966           pasteboard_name = [NSString stringWithFormat:@"_GTK_%@", 
967                              [NSString stringWithUTF8String:atom_string]];
968           g_free (atom_string);
969         }
970
971       clipboard->pasteboard = [NSPasteboard pasteboardWithName:pasteboard_name];
972
973       [pool release];
974
975       clipboard->selection = selection;
976       clipboard->display = display;
977       clipboard->n_cached_targets = -1;
978       clipboard->n_storable_targets = -1;
979       clipboards = g_slist_prepend (clipboards, clipboard);
980       g_object_set_data (G_OBJECT (display), I_("gtk-clipboard-list"), clipboards);
981       g_signal_connect (display, "closed",
982                         G_CALLBACK (clipboard_display_closed), clipboard);
983       gdk_display_request_selection_notification (display, selection);
984     }
985   
986   return clipboard;
987 }
988
989 static void
990 gtk_clipboard_owner_change (GtkClipboard        *clipboard,
991                             GdkEventOwnerChange *event)
992 {
993   if (clipboard->n_cached_targets != -1)
994     {
995       clipboard->n_cached_targets = -1;
996       g_free (clipboard->cached_targets);
997     }
998 }
999
1000 gboolean
1001 gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
1002                                         GdkAtom       target)
1003 {
1004   GdkAtom *targets;
1005   gint i, n_targets;
1006   gboolean retval = FALSE;
1007     
1008   if (!gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets))
1009     return FALSE;
1010
1011   for (i = 0; i < n_targets; i++)
1012     {
1013       if (targets[i] == target)
1014         {
1015           retval = TRUE;
1016           break;
1017         }
1018     }
1019
1020   g_free (targets);
1021   
1022   return retval;
1023 }
1024
1025 void 
1026 _gtk_clipboard_handle_event (GdkEventOwnerChange *event)
1027 {
1028 }
1029
1030 void
1031 gtk_clipboard_set_can_store (GtkClipboard         *clipboard,
1032                              const GtkTargetEntry *targets,
1033                              gint                  n_targets)
1034 {
1035   /* FIXME: Implement */
1036 }
1037
1038 void
1039 gtk_clipboard_store (GtkClipboard *clipboard)
1040 {
1041   /* FIXME: Implement */
1042 }
1043
1044 void
1045 _gtk_clipboard_store_all (void)
1046 {
1047   /* FIXME: Implement */
1048 }