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