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