]> Pileus Git - ~andy/gtk/blob - gtk/gtkclipboard-quartz.c
Updated Portuguese translation
[~andy/gtk] / gtk / gtkclipboard-quartz.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  * Copyright (C) 2004 Nokia Corporation
4  * Copyright (C) 2006-2008 Imendio AB
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "config.h"
22 #include <string.h>
23
24 #import <Cocoa/Cocoa.h>
25
26 #include "gtkclipboard.h"
27 #include "gtkinvisible.h"
28 #include "gtkmain.h"
29 #include "gtkmarshalers.h"
30 #include "gtkintl.h"
31 #include "gtktextbuffer.h"
32 #include "gtkselectionprivate.h"
33 #include "gtkquartz.h"
34
35
36 enum {
37   OWNER_CHANGE,
38   LAST_SIGNAL
39 };
40
41 typedef struct _GtkClipboardClass GtkClipboardClass;
42
43 struct _GtkClipboard 
44 {
45   GObject parent_instance;
46
47   NSPasteboard *pasteboard;
48
49   GdkAtom selection;
50
51   GtkClipboardGetFunc get_func;
52   GtkClipboardClearFunc clear_func;
53   gpointer user_data;
54   gboolean have_owner;
55   GtkTargetList *target_list;
56
57   gboolean have_selection;
58   GdkDisplay *display;
59
60   GdkAtom *cached_targets;
61   gint     n_cached_targets;
62
63   guint      notify_signal_id;
64   gboolean   storing_selection;
65   GMainLoop *store_loop;
66   guint      store_timeout;
67   gint       n_storable_targets;
68   GdkAtom   *storable_targets;
69 };
70
71 struct _GtkClipboardClass
72 {
73   GObjectClass parent_class;
74
75   void (*owner_change) (GtkClipboard        *clipboard,
76                         GdkEventOwnerChange *event);
77 };
78
79 @interface GtkClipboardOwner : NSObject {
80   GtkClipboard *clipboard;
81
82   GtkClipboardGetFunc get_func;
83   GtkClipboardClearFunc clear_func;
84   gpointer user_data;
85   
86 }
87
88 @end
89
90 @implementation GtkClipboardOwner
91 -(void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
92 {
93   GtkSelectionData selection_data;
94   guint info;
95
96   if (!clipboard->target_list)
97     return;
98
99   memset (&selection_data, 0, sizeof (GtkSelectionData));
100
101   selection_data.selection = clipboard->selection;
102   selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type);
103   selection_data.display = gdk_display_get_default ();
104   selection_data.length = -1;
105
106   if (gtk_target_list_find (clipboard->target_list, selection_data.target, &info))
107     {
108       clipboard->get_func (clipboard, &selection_data,
109                            info,
110                            clipboard->user_data);
111
112       if (selection_data.length >= 0)
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 /**
251  * gtk_clipboard_get_for_display:
252  * @display: the display for which the clipboard is to be retrieved or created
253  * @selection: a #GdkAtom which identifies the clipboard to use.
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 /**
266  * gtk_clipboard_get:
267  * @selection: a #GdkAtom which identifies the clipboard to use
268  */
269 GtkClipboard *
270 gtk_clipboard_get (GdkAtom selection)
271 {
272   return gtk_clipboard_get_for_display (gdk_display_get_default (), selection);
273 }
274
275 static void
276 clipboard_owner_destroyed (gpointer data)
277 {
278   GSList *clipboards = data;
279   GSList *tmp_list;
280
281   tmp_list = clipboards;
282   while (tmp_list)
283     {
284       GtkClipboard *clipboard = tmp_list->data;
285
286       clipboard->get_func = NULL;
287       clipboard->clear_func = NULL;
288       clipboard->user_data = NULL;
289       clipboard->have_owner = FALSE;
290
291       if (clipboard->target_list)
292         {
293           gtk_target_list_unref (clipboard->target_list);
294           clipboard->target_list = NULL;
295         }
296
297       gtk_clipboard_clear (clipboard);
298
299       tmp_list = tmp_list->next;
300     }
301   
302   g_slist_free (clipboards);
303 }
304
305 static void
306 clipboard_add_owner_notify (GtkClipboard *clipboard)
307 {
308   if (!clipboards_owned_key_id)
309     clipboards_owned_key_id = g_quark_from_static_string (clipboards_owned_key);
310   
311   if (clipboard->have_owner)
312     g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
313                              g_slist_prepend (g_object_steal_qdata (clipboard->user_data,
314                                                                     clipboards_owned_key_id),
315                                               clipboard),
316                              clipboard_owner_destroyed);
317 }
318
319 static void
320 clipboard_remove_owner_notify (GtkClipboard *clipboard)
321 {
322   if (clipboard->have_owner)
323      g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
324                               g_slist_remove (g_object_steal_qdata (clipboard->user_data,
325                                                                     clipboards_owned_key_id),
326                                               clipboard),
327                               clipboard_owner_destroyed);
328 }
329
330 static gboolean
331 gtk_clipboard_set_contents (GtkClipboard         *clipboard,
332                             const GtkTargetEntry *targets,
333                             guint                 n_targets,
334                             GtkClipboardGetFunc   get_func,
335                             GtkClipboardClearFunc clear_func,
336                             gpointer              user_data,
337                             gboolean              have_owner)
338 {
339   GtkClipboardOwner *owner;
340   NSSet *types;
341   NSAutoreleasePool *pool;
342
343   pool = [[NSAutoreleasePool alloc] init];
344
345   owner = [[GtkClipboardOwner alloc] initWithClipboard:clipboard];
346
347   if (!(clipboard->have_owner && have_owner) ||
348       clipboard->user_data != user_data)
349     {
350       clipboard_unset (clipboard);
351
352       if (clipboard->get_func)
353         {
354           /* Calling unset() caused the clipboard contents to be reset!
355            * Avoid leaking and return
356            */
357           if (!(clipboard->have_owner && have_owner) ||
358               clipboard->user_data != user_data)
359             {
360               (*clear_func) (clipboard, user_data);
361               [pool release];
362               return FALSE;
363             }
364           else
365             {
366               [pool release];
367               return TRUE;
368             }
369         }
370     }
371
372   clipboard->user_data = user_data;
373   clipboard->have_owner = have_owner;
374   if (have_owner)
375     clipboard_add_owner_notify (clipboard);
376   clipboard->get_func = get_func;
377   clipboard->clear_func = clear_func;
378
379   if (clipboard->target_list)
380     gtk_target_list_unref (clipboard->target_list);
381   clipboard->target_list = gtk_target_list_new (targets, n_targets);
382
383   types = _gtk_quartz_target_entries_to_pasteboard_types (targets, n_targets);
384
385   [clipboard->pasteboard declareTypes:[types allObjects] owner:owner];
386   [types release];
387   [pool release];
388
389   return TRUE;
390 }
391
392 /**
393  * gtk_clipboard_set_with_data: (skip)
394  * @clipboard: a #GtkClipboard
395  * @targets: (array length=n_targets): array containing information
396  *     about the available forms for the clipboard data
397  * @n_targets: number of elements in @targets
398  * @get_func: (scope async): function to call to get the actual clipboard data
399  * @clear_func: (scope async): when the clipboard contents are set again,
400  *     this function will be called, and @get_func will not be subsequently
401  *     called.
402  * @user_data: user data to pass to @get_func and @clear_func.
403  */
404 gboolean
405 gtk_clipboard_set_with_data (GtkClipboard          *clipboard,
406                              const GtkTargetEntry  *targets,
407                              guint                  n_targets,
408                              GtkClipboardGetFunc    get_func,
409                              GtkClipboardClearFunc  clear_func,
410                              gpointer               user_data)
411 {
412   g_return_val_if_fail (clipboard != NULL, FALSE);
413   g_return_val_if_fail (targets != NULL, FALSE);
414   g_return_val_if_fail (get_func != NULL, FALSE);
415
416   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
417                                      get_func, clear_func, user_data,
418                                      FALSE);
419 }
420
421 /**
422  * gtk_clipboard_set_with_owner: (skip)
423  * @clipboard: a #GtkClipboard
424  * @targets: (array length=n_targets): array containing information
425  *     about the available forms for the clipboard data
426  * @n_targets: number of elements in @targets
427  * @get_func: (scope async): function to call to get the actual clipboard data
428  * @clear_func: (scope async): when the clipboard contents are set again,
429  *     this function will be called, and @get_func will not be subsequently
430  *     called
431  * @owner: an object that "owns" the data. This object will be passed
432  *     to the callbacks when called
433  */
434 gboolean
435 gtk_clipboard_set_with_owner (GtkClipboard          *clipboard,
436                               const GtkTargetEntry  *targets,
437                               guint                  n_targets,
438                               GtkClipboardGetFunc    get_func,
439                               GtkClipboardClearFunc  clear_func,
440                               GObject               *owner)
441 {
442   g_return_val_if_fail (clipboard != NULL, FALSE);
443   g_return_val_if_fail (targets != NULL, FALSE);
444   g_return_val_if_fail (get_func != NULL, FALSE);
445   g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
446
447   return gtk_clipboard_set_contents (clipboard, targets, n_targets,
448                                      get_func, clear_func, owner,
449                                      TRUE);
450 }
451
452 /**
453  * gtk_clipboard_get_owner:
454  * @clipboard: a #GtkClipboard
455  */
456 GObject *
457 gtk_clipboard_get_owner (GtkClipboard *clipboard)
458 {
459   g_return_val_if_fail (clipboard != NULL, NULL);
460
461   if (clipboard->have_owner)
462     return clipboard->user_data;
463   else
464     return NULL;
465 }
466
467 static void
468 clipboard_unset (GtkClipboard *clipboard)
469 {
470   GtkClipboardClearFunc old_clear_func;
471   gpointer old_data;
472   gboolean old_have_owner;
473   gint old_n_storable_targets;
474   
475   old_clear_func = clipboard->clear_func;
476   old_data = clipboard->user_data;
477   old_have_owner = clipboard->have_owner;
478   old_n_storable_targets = clipboard->n_storable_targets;
479   
480   if (old_have_owner)
481     {
482       clipboard_remove_owner_notify (clipboard);
483       clipboard->have_owner = FALSE;
484     }
485
486   clipboard->n_storable_targets = -1;
487   g_free (clipboard->storable_targets);
488   clipboard->storable_targets = NULL;
489       
490   clipboard->get_func = NULL;
491   clipboard->clear_func = NULL;
492   clipboard->user_data = NULL;
493   
494   if (old_clear_func)
495     old_clear_func (clipboard, old_data);
496
497   if (clipboard->target_list)
498     {
499       gtk_target_list_unref (clipboard->target_list);
500       clipboard->target_list = NULL;
501     }
502
503   /* If we've transferred the clipboard data to the manager,
504    * unref the owner
505    */
506   if (old_have_owner &&
507       old_n_storable_targets != -1)
508     g_object_unref (old_data);
509 }
510
511 /**
512  * gtk_clipboard_clear:
513  * @clipboard:  a #GtkClipboard
514  */
515 void
516 gtk_clipboard_clear (GtkClipboard *clipboard)
517 {
518   [clipboard->pasteboard declareTypes:nil owner:nil];
519 }
520
521 static void 
522 text_get_func (GtkClipboard     *clipboard,
523                GtkSelectionData *selection_data,
524                guint             info,
525                gpointer          data)
526 {
527   gtk_selection_data_set_text (selection_data, data, -1);
528 }
529
530 static void 
531 text_clear_func (GtkClipboard *clipboard,
532                  gpointer      data)
533 {
534   g_free (data);
535 }
536
537 /**
538  * gtk_clipboard_set_text:
539  * @clipboard: a #GtkClipboard object
540  * @text:      a UTF-8 string.
541  * @len:       length of @text, in bytes, or -1, in which case
542  *             the length will be determined with <function>strlen()</function>.
543  */
544 void 
545 gtk_clipboard_set_text (GtkClipboard *clipboard,
546                         const gchar  *text,
547                         gint          len)
548 {
549   GtkTargetEntry target = { "UTF8_STRING", 0, 0 };
550
551   g_return_if_fail (clipboard != NULL);
552   g_return_if_fail (text != NULL);
553   
554   if (len < 0)
555     len = strlen (text);
556   
557   gtk_clipboard_set_with_data (clipboard, 
558                                &target, 1,
559                                text_get_func, text_clear_func,
560                                g_strndup (text, len));
561   gtk_clipboard_set_can_store (clipboard, NULL, 0);
562 }
563
564
565 static void 
566 pixbuf_get_func (GtkClipboard     *clipboard,
567                  GtkSelectionData *selection_data,
568                  guint             info,
569                  gpointer          data)
570 {
571   gtk_selection_data_set_pixbuf (selection_data, data);
572 }
573
574 static void 
575 pixbuf_clear_func (GtkClipboard *clipboard,
576                    gpointer      data)
577 {
578   g_object_unref (data);
579 }
580
581 /**
582  * gtk_clipboard_set_image:
583  * @clipboard: a #GtkClipboard object
584  * @pixbuf:    a #GdkPixbuf 
585  */
586 void
587 gtk_clipboard_set_image (GtkClipboard *clipboard,
588                          GdkPixbuf    *pixbuf)
589 {
590   GtkTargetList *list;
591   GList *l;
592   GtkTargetEntry *targets;
593   gint n_targets, i;
594
595   g_return_if_fail (clipboard != NULL);
596   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
597
598   list = gtk_target_list_new (NULL, 0);
599   gtk_target_list_add_image_targets (list, 0, TRUE);
600
601   n_targets = g_list_length (list->list);
602   targets = g_new0 (GtkTargetEntry, n_targets);
603   for (l = list->list, i = 0; l; l = l->next, i++)
604     {
605       GtkTargetPair *pair = (GtkTargetPair *)l->data;
606       targets[i].target = gdk_atom_name (pair->target);
607     }
608
609   gtk_clipboard_set_with_data (clipboard, 
610                                targets, n_targets,
611                                pixbuf_get_func, pixbuf_clear_func,
612                                g_object_ref (pixbuf));
613   gtk_clipboard_set_can_store (clipboard, NULL, 0);
614
615   for (i = 0; i < n_targets; i++)
616     g_free (targets[i].target);
617   g_free (targets);
618   gtk_target_list_unref (list);
619 }
620
621 /**
622  * gtk_clipboard_request_contents:
623  * @clipboard: a #GtkClipboard
624  * @target: an atom representing the form into which the clipboard
625  *     owner should convert the selection.
626  * @callback: (scope async): A function to call when the results are received
627  *     (or the retrieval fails). If the retrieval fails the length field of
628  *     @selection_data will be negative.
629  * @user_data: user data to pass to @callback
630  */
631 void 
632 gtk_clipboard_request_contents (GtkClipboard            *clipboard,
633                                 GdkAtom                  target,
634                                 GtkClipboardReceivedFunc callback,
635                                 gpointer                 user_data)
636 {
637   GtkSelectionData *data;
638
639   data = gtk_clipboard_wait_for_contents (clipboard, target);
640
641   callback (clipboard, data, user_data);
642
643   gtk_selection_data_free (data);
644 }
645
646 /**
647  * gtk_clipboard_request_text:
648  * @clipboard: a #GtkClipboard
649  * @callback: (scope async): a function to call when the text is received,
650  *     or the retrieval fails. (It will always be called one way or the other.)
651  * @user_data: user data to pass to @callback.
652  */
653 void 
654 gtk_clipboard_request_text (GtkClipboard                *clipboard,
655                             GtkClipboardTextReceivedFunc callback,
656                             gpointer                     user_data)
657 {
658   gchar *data = gtk_clipboard_wait_for_text (clipboard);
659
660   callback (clipboard, data, user_data);
661
662   g_free (data);
663 }
664
665 /**
666  * gtk_clipboard_request_rich_text:
667  * @clipboard: a #GtkClipboard
668  * @buffer: a #GtkTextBuffer
669  * @callback: (scope async): a function to call when the text is received,
670  *     or the retrieval fails. (It will always be called one way or the other.)
671  * @user_data: user data to pass to @callback.
672  */
673 void
674 gtk_clipboard_request_rich_text (GtkClipboard                    *clipboard,
675                                  GtkTextBuffer                   *buffer,
676                                  GtkClipboardRichTextReceivedFunc callback,
677                                  gpointer                         user_data)
678 {
679   /* FIXME: Implement */
680 }
681
682
683 guint8 *
684 gtk_clipboard_wait_for_rich_text (GtkClipboard  *clipboard,
685                                   GtkTextBuffer *buffer,
686                                   GdkAtom       *format,
687                                   gsize         *length)
688 {
689   /* FIXME: Implement */
690   return NULL;
691 }
692
693 /**
694  * gtk_clipboard_request_image:
695  * @clipboard: a #GtkClipboard
696  * @callback: (scope async): a function to call when the image is received,
697  *     or the retrieval fails. (It will always be called one way or the other.)
698  * @user_data: user data to pass to @callback.
699  */
700 void 
701 gtk_clipboard_request_image (GtkClipboard                  *clipboard,
702                              GtkClipboardImageReceivedFunc  callback,
703                              gpointer                       user_data)
704 {
705   GdkPixbuf *pixbuf = gtk_clipboard_wait_for_image (clipboard);
706
707   callback (clipboard, pixbuf, user_data);
708
709   if (pixbuf)
710     g_object_unref (pixbuf);
711 }
712
713 /**
714  * gtk_clipboard_request_uris:
715  * @clipboard: a #GtkClipboard
716  * @callback: (scope async): a function to call when the URIs are received,
717  *     or the retrieval fails. (It will always be called one way or the other.)
718  * @user_data: user data to pass to @callback.
719  */
720 void 
721 gtk_clipboard_request_uris (GtkClipboard                *clipboard,
722                             GtkClipboardURIReceivedFunc  callback,
723                             gpointer                     user_data)
724 {
725   gchar **uris = gtk_clipboard_wait_for_uris (clipboard);
726
727   callback (clipboard, uris, user_data);
728
729   g_strfreev (uris);
730 }
731
732 /**
733  * gtk_clipboard_request_targets:
734  * @clipboard: a #GtkClipboard
735  * @callback: (scope async): a function to call when the targets are
736  *     received, or the retrieval fails. (It will always be called
737  *     one way or the other.)
738  * @user_data: user data to pass to @callback.
739  */
740 void 
741 gtk_clipboard_request_targets (GtkClipboard                *clipboard,
742                                GtkClipboardTargetsReceivedFunc callback,
743                                gpointer                     user_data)
744 {
745   GdkAtom *targets;
746   gint n_targets;
747
748   gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets);
749
750   callback (clipboard, targets, n_targets, user_data);
751 }
752
753
754 /**
755  * gtk_clipboard_wait_for_contents:
756  * @clipboard: a #GtkClipboard
757  * @target: an atom representing the form into which the clipboard
758  *          owner should convert the selection.
759  */
760 GtkSelectionData *
761 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
762                                  GdkAtom       target)
763 {
764   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
765   GtkSelectionData *selection_data = NULL;
766
767   if (target == gdk_atom_intern_static_string ("TARGETS")) 
768     {
769       NSArray *types = [clipboard->pasteboard types];
770       int i, length;
771       GList *atom_list, *l;
772       GdkAtom *atoms;
773
774       length = [types count] * sizeof (GdkAtom);
775       
776       selection_data = g_slice_new0 (GtkSelectionData);
777       selection_data->selection = clipboard->selection;
778       selection_data->target = target;
779
780       atoms = g_malloc (length);
781
782       atom_list = _gtk_quartz_pasteboard_types_to_atom_list (types);
783       for (l = atom_list, i = 0; l ; l = l->next, i++)
784         atoms[i] = GDK_POINTER_TO_ATOM (l->data);
785       g_list_free (atom_list);
786
787       gtk_selection_data_set (selection_data,
788                               GDK_SELECTION_TYPE_ATOM, 32,
789                               (guchar *)atoms, length);
790
791       [pool release];
792
793       return selection_data;
794     }
795
796   selection_data = _gtk_quartz_get_selection_data_from_pasteboard (clipboard->pasteboard,
797                                                                    target,
798                                                                    clipboard->selection);
799
800   [pool release];
801
802   return selection_data;
803 }
804
805 /**
806  * gtk_clipboard_wait_for_text:
807  * @clipboard: a #GtkClipboard
808  */
809 gchar *
810 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
811 {
812   GtkSelectionData *data;
813   gchar *result;
814
815   data = gtk_clipboard_wait_for_contents (clipboard, 
816                                           gdk_atom_intern_static_string ("UTF8_STRING"));
817
818   result = (gchar *)gtk_selection_data_get_text (data);
819
820   gtk_selection_data_free (data);
821
822   return result;
823 }
824
825 /**
826  * gtk_clipboard_wait_for_image:
827  * @clipboard: a #GtkClipboard
828  */
829 GdkPixbuf *
830 gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
831 {
832   const gchar *priority[] = { "image/png", "image/tiff", "image/jpeg", "image/gif", "image/bmp" };
833   int i;
834   GtkSelectionData *data;
835
836   for (i = 0; i < G_N_ELEMENTS (priority); i++) 
837     {    
838       data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string (priority[i]));
839
840       if (data)
841         {
842           GdkPixbuf *pixbuf = gtk_selection_data_get_pixbuf (data);
843
844           gtk_selection_data_free (data);
845
846           return pixbuf;
847         }  
848   }
849
850   return NULL;
851 }
852
853 /**
854  * gtk_clipboard_wait_for_uris:
855  * @clipboard: a #GtkClipboard
856  */
857 gchar **
858 gtk_clipboard_wait_for_uris (GtkClipboard *clipboard)
859 {
860   GtkSelectionData *data;
861
862   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("text/uri-list"));
863   if (data)
864     {
865       gchar **uris;
866
867       uris = gtk_selection_data_get_uris (data);
868       gtk_selection_data_free (data);
869
870       return uris;
871     }  
872
873   return NULL;
874 }
875
876 /**
877  * gtk_clipboard_get_display:
878  * @clipboard: a #GtkClipboard
879  */
880 GdkDisplay *
881 gtk_clipboard_get_display (GtkClipboard *clipboard)
882 {
883   g_return_val_if_fail (clipboard != NULL, NULL);
884
885   return clipboard->display;
886 }
887
888 /**
889  * gtk_clipboard_wait_is_text_available:
890  * @clipboard: a #GtkClipboard
891  */
892 gboolean
893 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
894 {
895   GtkSelectionData *data;
896   gboolean result = FALSE;
897
898   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
899   if (data)
900     {
901       result = gtk_selection_data_targets_include_text (data);
902       gtk_selection_data_free (data);
903     }
904
905   return result;
906 }
907
908 /**
909  * gtk_clipboard_wait_is_rich_text_available:
910  * @clipboard: a #GtkClipboard
911  * @buffer: a #GtkTextBuffer
912  */
913 gboolean
914 gtk_clipboard_wait_is_rich_text_available (GtkClipboard  *clipboard,
915                                            GtkTextBuffer *buffer)
916 {
917   GtkSelectionData *data;
918   gboolean result = FALSE;
919
920   g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
921   g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
922
923   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
924   if (data)
925     {
926       result = gtk_selection_data_targets_include_rich_text (data, buffer);
927       gtk_selection_data_free (data);
928     }
929
930   return result;
931 }
932
933 /**
934  * gtk_clipboard_wait_is_image_available:
935  * @clipboard: a #GtkClipboard
936  */
937 gboolean
938 gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
939 {
940   GtkSelectionData *data;
941   gboolean result = FALSE;
942
943   data = gtk_clipboard_wait_for_contents (clipboard, 
944                                           gdk_atom_intern_static_string ("TARGETS"));
945   if (data)
946     {
947       result = gtk_selection_data_targets_include_image (data, FALSE);
948       gtk_selection_data_free (data);
949     }
950
951   return result;
952 }
953
954 /**
955  * gtk_clipboard_wait_is_uris_available:
956  * @clipboard: a #GtkClipboard
957  */
958 gboolean
959 gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard)
960 {
961   GtkSelectionData *data;
962   gboolean result = FALSE;
963
964   data = gtk_clipboard_wait_for_contents (clipboard, 
965                                           gdk_atom_intern_static_string ("TARGETS"));
966   if (data)
967     {
968       result = gtk_selection_data_targets_include_uri (data);
969       gtk_selection_data_free (data);
970     }
971
972   return result;
973 }
974
975 /**
976  * gtk_clipboard_wait_for_targets:
977  * @clipboard: a #GtkClipboard
978  * @targets: (out) (array length=n_targets) (transfer container): location
979  *           to store an array of targets. The result stored here must
980  *           be freed with g_free().
981  * @n_targets: location to store number of items in @targets.
982  */
983 gboolean
984 gtk_clipboard_wait_for_targets (GtkClipboard  *clipboard, 
985                                 GdkAtom      **targets,
986                                 gint          *n_targets)
987 {
988   GtkSelectionData *data;
989   gboolean result = FALSE;
990   
991   g_return_val_if_fail (clipboard != NULL, FALSE);
992
993   /* If the display supports change notification we cache targets */
994   if (gdk_display_supports_selection_notification (gtk_clipboard_get_display (clipboard)) &&
995       clipboard->n_cached_targets != -1)
996     {
997       if (n_targets)
998         *n_targets = clipboard->n_cached_targets;
999  
1000       if (targets)
1001         *targets = g_memdup (clipboard->cached_targets,
1002                              clipboard->n_cached_targets * sizeof (GdkAtom));
1003
1004        return TRUE;
1005     }
1006   
1007   if (n_targets)
1008     *n_targets = 0;
1009       
1010   if (targets)
1011     *targets = NULL;      
1012
1013   data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
1014
1015   if (data)
1016     {
1017       GdkAtom *tmp_targets;
1018       gint tmp_n_targets;
1019        
1020       result = gtk_selection_data_get_targets (data, &tmp_targets, &tmp_n_targets);
1021  
1022       if (gdk_display_supports_selection_notification (gtk_clipboard_get_display (clipboard)))
1023         {
1024           clipboard->n_cached_targets = tmp_n_targets;
1025           clipboard->cached_targets = g_memdup (tmp_targets,
1026                                                 tmp_n_targets * sizeof (GdkAtom));
1027         }
1028  
1029       if (n_targets)
1030         *n_targets = tmp_n_targets;
1031  
1032       if (targets)
1033         *targets = tmp_targets;
1034       else
1035         g_free (tmp_targets);
1036       
1037       gtk_selection_data_free (data);
1038     }
1039
1040   return result;
1041 }
1042
1043 static GtkClipboard *
1044 clipboard_peek (GdkDisplay *display, 
1045                 GdkAtom     selection,
1046                 gboolean    only_if_exists)
1047 {
1048   GtkClipboard *clipboard = NULL;
1049   GSList *clipboards;
1050   GSList *tmp_list;
1051
1052   if (selection == GDK_NONE)
1053     selection = GDK_SELECTION_CLIPBOARD;
1054
1055   clipboards = g_object_get_data (G_OBJECT (display), "gtk-clipboard-list");
1056
1057   tmp_list = clipboards;
1058   while (tmp_list)
1059     {
1060       clipboard = tmp_list->data;
1061       if (clipboard->selection == selection)
1062         break;
1063
1064       tmp_list = tmp_list->next;
1065     }
1066
1067   if (!tmp_list && !only_if_exists)
1068     {
1069       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1070       NSString *pasteboard_name;
1071       clipboard = g_object_new (GTK_TYPE_CLIPBOARD, NULL);
1072
1073       if (selection == GDK_SELECTION_CLIPBOARD) 
1074         pasteboard_name = NSGeneralPboard;
1075       else 
1076         {
1077           char *atom_string = gdk_atom_name (selection);
1078
1079           pasteboard_name = [NSString stringWithFormat:@"_GTK_%@", 
1080                              [NSString stringWithUTF8String:atom_string]];
1081           g_free (atom_string);
1082         }
1083
1084       clipboard->pasteboard = [NSPasteboard pasteboardWithName:pasteboard_name];
1085
1086       [pool release];
1087
1088       clipboard->selection = selection;
1089       clipboard->display = display;
1090       clipboard->n_cached_targets = -1;
1091       clipboard->n_storable_targets = -1;
1092       clipboards = g_slist_prepend (clipboards, clipboard);
1093       g_object_set_data (G_OBJECT (display), I_("gtk-clipboard-list"), clipboards);
1094       g_signal_connect (display, "closed",
1095                         G_CALLBACK (clipboard_display_closed), clipboard);
1096       gdk_display_request_selection_notification (display, selection);
1097     }
1098   
1099   return clipboard;
1100 }
1101
1102 static void
1103 gtk_clipboard_owner_change (GtkClipboard        *clipboard,
1104                             GdkEventOwnerChange *event)
1105 {
1106   if (clipboard->n_cached_targets != -1)
1107     {
1108       clipboard->n_cached_targets = -1;
1109       g_free (clipboard->cached_targets);
1110     }
1111 }
1112
1113 /**
1114  * gtk_clipboard_wait_is_target_available:
1115  * @clipboard: a #GtkClipboard
1116  * @target:    A #GdkAtom indicating which target to look for.
1117  */
1118 gboolean
1119 gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
1120                                         GdkAtom       target)
1121 {
1122   GdkAtom *targets;
1123   gint i, n_targets;
1124   gboolean retval = FALSE;
1125     
1126   if (!gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets))
1127     return FALSE;
1128
1129   for (i = 0; i < n_targets; i++)
1130     {
1131       if (targets[i] == target)
1132         {
1133           retval = TRUE;
1134           break;
1135         }
1136     }
1137
1138   g_free (targets);
1139   
1140   return retval;
1141 }
1142
1143 /**
1144  * _gtk_clipboard_handle_event:
1145  * @event: a owner change event
1146  */
1147 void 
1148 _gtk_clipboard_handle_event (GdkEventOwnerChange *event)
1149 {
1150 }
1151
1152 /**
1153  * gtk_clipboard_set_can_store:
1154  * @clipboard: a #GtkClipboard
1155  * @targets: (allow-none) (array length=n_targets): array containing
1156  *           information about which forms should be stored or %NULL
1157  *           to indicate that all forms should be stored.
1158  * @n_targets: number of elements in @targets
1159  */
1160 void
1161 gtk_clipboard_set_can_store (GtkClipboard         *clipboard,
1162                              const GtkTargetEntry *targets,
1163                              gint                  n_targets)
1164 {
1165   /* FIXME: Implement */
1166 }
1167
1168 /**
1169  * gtk_clipboard_store:
1170  * @clipboard: a #GtkClipboard
1171  */
1172 void
1173 gtk_clipboard_store (GtkClipboard *clipboard)
1174 {
1175   /* FIXME: Implement */
1176 }
1177
1178 void
1179 _gtk_clipboard_store_all (void)
1180 {
1181   /* FIXME: Implement */
1182 }