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