]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkclipboard-quartz.c
gtkfilechooserbutton: In tests, allow the possibility of doing unselect_all
[~andy/gtk] / gtk / gtkclipboard-quartz.c
index ba87b429739f2e84a75c4758a9da414d5e5981b0..482f6aa13518de0977cab81706e0423b2cd309c9 100644 (file)
@@ -1,7 +1,7 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 2000 Red Hat, Inc.
  * Copyright (C) 2004 Nokia Corporation
- * Copyright (C) 2006 Imendio AB
+ * Copyright (C) 2006-2008 Imendio AB
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  *
  */
 
-#include <config.h>
+#include "config.h"
 #include <string.h>
 
 #import <Cocoa/Cocoa.h>
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkintl.h"
-#include "gtkalias.h"
 #include "gtktextbuffer.h"
-
+#include "gtkselectionprivate.h"
 #include "gtkquartz.h"
+#include "../gdk/quartz/gdkquartz.h"
 
 enum {
   OWNER_CHANGE,
   LAST_SIGNAL
 };
 
+@interface GtkClipboardOwner : NSObject {
+  GtkClipboard *clipboard;
+  @public
+  gboolean setting_same_owner;
+}
+
+@end
+
 typedef struct _GtkClipboardClass GtkClipboardClass;
 
-struct _GtkClipboard 
+struct _GtkClipboard
 {
   GObject parent_instance;
 
   NSPasteboard *pasteboard;
+  GtkClipboardOwner *owner;
+  NSInteger change_count;
 
   GdkAtom selection;
 
@@ -54,6 +62,7 @@ struct _GtkClipboard
   GtkClipboardClearFunc clear_func;
   gpointer user_data;
   gboolean have_owner;
+  GtkTargetList *target_list;
 
   gboolean have_selection;
   GdkDisplay *display;
@@ -77,43 +86,56 @@ struct _GtkClipboardClass
                        GdkEventOwnerChange *event);
 };
 
-@interface GtkClipboardOwner : NSObject {
-  GtkClipboard *clipboard;
-
-  GtkClipboardGetFunc get_func;
-  GtkClipboardClearFunc clear_func;
-  gpointer user_data;
-  
-}
+static void gtk_clipboard_class_init   (GtkClipboardClass   *class);
+static void gtk_clipboard_finalize     (GObject             *object);
+static void gtk_clipboard_owner_change (GtkClipboard        *clipboard,
+                                       GdkEventOwnerChange *event);
 
-@end
+static void          clipboard_unset      (GtkClipboard     *clipboard);
+static GtkClipboard *clipboard_peek       (GdkDisplay       *display,
+                                          GdkAtom           selection,
+                                          gboolean          only_if_exists);
 
 @implementation GtkClipboardOwner
 -(void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
 {
   GtkSelectionData selection_data;
+  guint info;
+
+  if (!clipboard->target_list)
+    return;
+
+  memset (&selection_data, 0, sizeof (GtkSelectionData));
 
   selection_data.selection = clipboard->selection;
-  selection_data.data = NULL;
   selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type);
+  selection_data.display = gdk_display_get_default ();
+  selection_data.length = -1;
 
-  /* FIXME: We need to find out what the info argument should be
-   * here by storing it in the clipboard object in
-   * gtk_clipboard_set_contents
-   */
-  clipboard->get_func (clipboard, &selection_data, 0, clipboard->user_data);
+  if (gtk_target_list_find (clipboard->target_list, selection_data.target, &info))
+    {
+      clipboard->get_func (clipboard, &selection_data,
+                           info,
+                           clipboard->user_data);
 
-  _gtk_quartz_set_selection_data_for_pasteboard (clipboard->pasteboard, &selection_data);
+      if (selection_data.length >= 0)
+        _gtk_quartz_set_selection_data_for_pasteboard (clipboard->pasteboard,
+                                                       &selection_data);
 
-  g_free (selection_data.data);
+      g_free (selection_data.data);
+    }
 }
 
+/*  pasteboardChangedOwner is not called immediately, and it's not called
+ *  reliably. It is somehow documented in the apple api docs, but the docs
+ *  suck and don't really give clear instructions. Therefore we track
+ *  changeCount in several places below and clear the clipboard if it
+ *  changed.
+ */
 - (void)pasteboardChangedOwner:(NSPasteboard *)sender
 {
-  if (clear_func)
-    clear_func (clipboard, user_data);
-
-  [self release];
+  if (! setting_same_owner)
+    clipboard_unset (clipboard);
 }
 
 - (id)initWithClipboard:(GtkClipboard *)aClipboard
@@ -123,6 +145,7 @@ struct _GtkClipboardClass
   if (self) 
     {
       clipboard = aClipboard;
+      setting_same_owner = FALSE;
     }
 
   return self;
@@ -130,15 +153,6 @@ struct _GtkClipboardClass
 
 @end
 
-static void gtk_clipboard_class_init   (GtkClipboardClass   *class);
-static void gtk_clipboard_finalize     (GObject             *object);
-static void gtk_clipboard_owner_change (GtkClipboard        *clipboard,
-                                       GdkEventOwnerChange *event);
-
-static void          clipboard_unset      (GtkClipboard     *clipboard);
-static GtkClipboard *clipboard_peek       (GdkDisplay       *display,
-                                          GdkAtom           selection,
-                                          gboolean          only_if_exists);
 
 static const gchar clipboards_owned_key[] = "gtk-clipboards-owned";
 static GQuark clipboards_owned_key_id = 0;
@@ -153,7 +167,7 @@ gtk_clipboard_get_type (void)
   
   if (!clipboard_type)
     {
-      static const GTypeInfo clipboard_info =
+      const GTypeInfo clipboard_info =
       {
        sizeof (GtkClipboardClass),
        NULL,           /* base_init */
@@ -185,7 +199,7 @@ gtk_clipboard_class_init (GtkClipboardClass *class)
   class->owner_change = gtk_clipboard_owner_change;
 
   clipboard_signals[OWNER_CHANGE] =
-    g_signal_new (I_("owner_change"),
+    g_signal_new (I_("owner-change"),
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkClipboardClass, owner_change),
@@ -238,73 +252,16 @@ clipboard_display_closed (GdkDisplay   *display,
   g_object_unref (clipboard);
 }
 
-/**
- * gtk_clipboard_get_for_display:
- * @display: the display for which the clipboard is to be retrieved or created
- * @selection: a #GdkAtom which identifies the clipboard
- *             to use.
- * 
- * Returns the clipboard object for the given selection.
- * Cut/copy/paste menu items and keyboard shortcuts should use
- * the default clipboard, returned by passing %GDK_SELECTION_CLIPBOARD for @selection.
- * (%GDK_NONE is supported as a synonym for GDK_SELECTION_CLIPBOARD
- * for backwards compatibility reasons.)
- * The currently-selected object or text should be provided on the clipboard
- * identified by #GDK_SELECTION_PRIMARY. Cut/copy/paste menu items
- * conceptually copy the contents of the #GDK_SELECTION_PRIMARY clipboard
- * to the default clipboard, i.e. they copy the selection to what the
- * user sees as the clipboard.
- *
- * (Passing #GDK_NONE is the same as using <literal>gdk_atom_intern
- * ("CLIPBOARD", FALSE)</literal>. See <ulink
- * url="http://www.freedesktop.org/Standards/clipboards-spec">
- * http://www.freedesktop.org/Standards/clipboards-spec</ulink>
- * for a detailed discussion of the "CLIPBOARD" vs. "PRIMARY"
- * selections under the X window system. On Win32 the
- * #GDK_SELECTION_PRIMARY clipboard is essentially ignored.)
- *
- * It's possible to have arbitrary named clipboards; if you do invent
- * new clipboards, you should prefix the selection name with an
- * underscore (because the ICCCM requires that nonstandard atoms are
- * underscore-prefixed), and namespace it as well. For example,
- * if your application called "Foo" has a special-purpose
- * clipboard, you might call it "_FOO_SPECIAL_CLIPBOARD".
- * 
- * Return value: the appropriate clipboard object. If no
- *             clipboard already exists, a new one will
- *             be created. Once a clipboard object has
- *             been created, it is persistent and, since
- *             it is owned by GTK+, must not be freed or
- *             unrefd.
- *
- * Since: 2.2
- **/
 GtkClipboard *
-gtk_clipboard_get_for_display (GdkDisplay *display, 
+gtk_clipboard_get_for_display (GdkDisplay *display,
                               GdkAtom     selection)
 {
   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-  g_return_val_if_fail (!display->closed, NULL);
+  g_return_val_if_fail (!gdk_display_is_closed (display), NULL);
 
   return clipboard_peek (display, selection, FALSE);
 }
 
-
-/**
- * gtk_clipboard_get():
- * @selection: a #GdkAtom which identifies the clipboard
- *             to use.
- * 
- * Returns the clipboard object for the given selection.
- * See gtk_clipboard_get_for_display() for complete details.
- * 
- * Return value: the appropriate clipboard object. If no
- *             clipboard already exists, a new one will
- *             be created. Once a clipboard object has
- *             been created, it is persistent and, since
- *             it is owned by GTK+, must not be freed or
- *             unrefd.
- **/
 GtkClipboard *
 gtk_clipboard_get (GdkAtom selection)
 {
@@ -327,6 +284,12 @@ clipboard_owner_destroyed (gpointer data)
       clipboard->user_data = NULL;
       clipboard->have_owner = FALSE;
 
+      if (clipboard->target_list)
+        {
+          gtk_target_list_unref (clipboard->target_list);
+          clipboard->target_list = NULL;
+        }
+
       gtk_clipboard_clear (clipboard);
 
       tmp_list = tmp_list->next;
@@ -370,15 +333,61 @@ gtk_clipboard_set_contents (GtkClipboard         *clipboard,
                            gboolean              have_owner)
 {
   GtkClipboardOwner *owner;
-  NSArray *types;
+  NSSet *types;
   NSAutoreleasePool *pool;
 
-  pool = [[NSAutoreleasePool alloc] init];
+  if (!(clipboard->have_owner && have_owner) ||
+      clipboard->user_data != user_data)
+    {
+      clipboard_unset (clipboard);
+
+      if (clipboard->get_func)
+        {
+          /* Calling unset() caused the clipboard contents to be reset!
+           * Avoid leaking and return
+           */
+          if (!(clipboard->have_owner && have_owner) ||
+              clipboard->user_data != user_data)
+            {
+              (*clear_func) (clipboard, user_data);
+              return FALSE;
+            }
+          else
+            {
+              return TRUE;
+            }
+        }
+    }
 
-  owner = [[GtkClipboardOwner alloc] initWithClipboard:clipboard];
+  pool = [[NSAutoreleasePool alloc] init];
 
   types = _gtk_quartz_target_entries_to_pasteboard_types (targets, n_targets);
 
+  /*  call declareTypes before setting the clipboard members because
+   *  declareTypes might clear the clipboard
+   */
+  if (user_data && user_data == clipboard->user_data)
+    {
+      owner = [clipboard->owner retain];
+
+      owner->setting_same_owner = TRUE;
+      clipboard->change_count = [clipboard->pasteboard declareTypes: [types allObjects]
+                                                              owner: owner];
+      owner->setting_same_owner = FALSE;
+    }
+  else
+    {
+      owner = [[GtkClipboardOwner alloc] initWithClipboard:clipboard];
+
+      clipboard->change_count = [clipboard->pasteboard declareTypes: [types allObjects]
+                                                              owner: owner];
+    }
+
+  [owner release];
+  [types release];
+  [pool release];
+
+  clipboard->owner = owner;
   clipboard->user_data = user_data;
   clipboard->have_owner = have_owner;
   if (have_owner)
@@ -386,32 +395,13 @@ gtk_clipboard_set_contents (GtkClipboard         *clipboard,
   clipboard->get_func = get_func;
   clipboard->clear_func = clear_func;
 
-  [clipboard->pasteboard declareTypes:types owner:owner];
+  if (clipboard->target_list)
+    gtk_target_list_unref (clipboard->target_list);
+  clipboard->target_list = gtk_target_list_new (targets, n_targets);
 
-  [pool release];
-
-  return true;
+  return TRUE;
 }
 
-/**
- * gtk_clipboard_set_with_data:
- * @clipboard:  a #GtkClipboard
- * @targets:    array containing information about the available forms for the
- *              clipboard data
- * @n_targets:  number of elements in @targets
- * @get_func:   function to call to get the actual clipboard data
- * @clear_func: when the clipboard contents are set again, this function will
- *              be called, and @get_func will not be subsequently called.
- * @user_data:  user data to pass to @get_func and @clear_func.
- * 
- * Virtually sets the contents of the specified clipboard by providing
- * a list of supported formats for the clipboard data and a function
- * to call to get the actual data when it is requested.
- * 
- * Return value: %TRUE if setting the clipboard data succeeded. If setting
- *               the clipboard data failed the provided callback functions
- *               will be ignored.
- **/
 gboolean
 gtk_clipboard_set_with_data (GtkClipboard          *clipboard,
                             const GtkTargetEntry  *targets,
@@ -429,30 +419,6 @@ gtk_clipboard_set_with_data (GtkClipboard          *clipboard,
                                     FALSE);
 }
 
-/**
- * gtk_clipboard_set_with_owner:
- * @clipboard:  a #GtkClipboard
- * @targets:    array containing information about the available forms for the
- *              clipboard data
- * @n_targets:  number of elements in @targets
- * @get_func:   function to call to get the actual clipboard data
- * @clear_func: when the clipboard contents are set again, this function will
- *              be called, and @get_func will not be subsequently called.
- * @owner:      an object that "owns" the data. This object will be passed
- *              to the callbacks when called. 
- * 
- * Virtually sets the contents of the specified clipboard by providing
- * a list of supported formats for the clipboard data and a function
- * to call to get the actual data when it is requested.
- *
- * The difference between this function and gtk_clipboard_set_with_data()
- * is that instead of an generic @user_data pointer, a #GObject is passed
- * in. 
- * 
- * Return value: %TRUE if setting the clipboard data succeeded. If setting
- *               the clipboard data failed the provided callback functions
- *               will be ignored.
- **/
 gboolean
 gtk_clipboard_set_with_owner (GtkClipboard          *clipboard,
                              const GtkTargetEntry  *targets,
@@ -471,22 +437,17 @@ gtk_clipboard_set_with_owner (GtkClipboard          *clipboard,
                                     TRUE);
 }
 
-/**
- * gtk_clipboard_get_owner:
- * @clipboard: a #GtkClipboard
- * 
- * If the clipboard contents callbacks were set with 
- * gtk_clipboard_set_with_owner(), and the gtk_clipboard_set_with_data() or 
- * gtk_clipboard_clear() has not subsequently called, returns the owner set 
- * by gtk_clipboard_set_with_owner().
- * 
- * Return value: the owner of the clipboard, if any; otherwise %NULL.
- **/
 GObject *
 gtk_clipboard_get_owner (GtkClipboard *clipboard)
 {
   g_return_val_if_fail (clipboard != NULL, NULL);
 
+  if (clipboard->change_count < [clipboard->pasteboard changeCount])
+    {
+      clipboard_unset (clipboard);
+      clipboard->change_count = [clipboard->pasteboard changeCount];
+    }
+
   if (clipboard->have_owner)
     return clipboard->user_data;
   else
@@ -508,13 +469,15 @@ clipboard_unset (GtkClipboard *clipboard)
   
   if (old_have_owner)
     {
+      clipboard_remove_owner_notify (clipboard);
       clipboard->have_owner = FALSE;
     }
 
   clipboard->n_storable_targets = -1;
   g_free (clipboard->storable_targets);
   clipboard->storable_targets = NULL;
-      
+
+  clipboard->owner = NULL;
   clipboard->get_func = NULL;
   clipboard->clear_func = NULL;
   clipboard->user_data = NULL;
@@ -522,6 +485,12 @@ clipboard_unset (GtkClipboard *clipboard)
   if (old_clear_func)
     old_clear_func (clipboard, old_data);
 
+  if (clipboard->target_list)
+    {
+      gtk_target_list_unref (clipboard->target_list);
+      clipboard->target_list = NULL;
+    }
+
   /* If we've transferred the clipboard data to the manager,
    * unref the owner
    */
@@ -530,19 +499,11 @@ clipboard_unset (GtkClipboard *clipboard)
     g_object_unref (old_data);
 }
 
-/**
- * gtk_clipboard_clear:
- * @clipboard:  a #GtkClipboard
- * 
- * Clears the contents of the clipboard. Generally this should only
- * be called between the time you call gtk_clipboard_set_with_owner()
- * or gtk_clipboard_set_with_data(),
- * and when the @clear_func you supplied is called. Otherwise, the
- * clipboard may be owned by someone else.
- **/
 void
 gtk_clipboard_clear (GtkClipboard *clipboard)
 {
+  clipboard_unset (clipboard);
+
   [clipboard->pasteboard declareTypes:nil owner:nil];
 }
 
@@ -562,18 +523,6 @@ text_clear_func (GtkClipboard *clipboard,
   g_free (data);
 }
 
-/**
- * gtk_clipboard_set_text:
- * @clipboard: a #GtkClipboard object
- * @text:      a UTF-8 string.
- * @len:       length of @text, in bytes, or -1, in which case
- *             the length will be determined with <function>strlen()</function>.
- * 
- * Sets the contents of the clipboard to the given UTF-8 string. GTK+ will
- * make a copy of the text and take responsibility for responding
- * for requests for the text, and for converting the text into
- * the requested format.
- **/
 void 
 gtk_clipboard_set_text (GtkClipboard *clipboard,
                        const gchar  *text,
@@ -611,18 +560,6 @@ pixbuf_clear_func (GtkClipboard *clipboard,
   g_object_unref (data);
 }
 
-/**
- * gtk_clipboard_set_image:
- * @clipboard: a #GtkClipboard object
- * @pixbuf:    a #GdkPixbuf 
- * 
- * Sets the contents of the clipboard to the given #GdkPixbuf. 
- * GTK+ will take responsibility for responding for requests 
- * for the image, and for converting the image into the 
- * requested format.
- * 
- * Since: 2.6
- **/
 void
 gtk_clipboard_set_image (GtkClipboard *clipboard,
                         GdkPixbuf    *pixbuf)
@@ -658,21 +595,6 @@ gtk_clipboard_set_image (GtkClipboard *clipboard,
   gtk_target_list_unref (list);
 }
 
-/**
- * gtk_clipboard_request_contents:
- * @clipboard: a #GtkClipboard
- * @target:    an atom representing the form into which the clipboard
- *             owner should convert the selection.
- * @callback:  A function to call when the results are received
- *             (or the retrieval fails). If the retrieval fails
- *             the length field of @selection_data will be
- *             negative.
- * @user_data: user data to pass to @callback
- * 
- * Requests the contents of clipboard as the given target.
- * When the results of the result are later received the supplied callback
- * will be called.
- **/
 void 
 gtk_clipboard_request_contents (GtkClipboard            *clipboard,
                                GdkAtom                  target,
@@ -688,23 +610,6 @@ gtk_clipboard_request_contents (GtkClipboard            *clipboard,
   gtk_selection_data_free (data);
 }
 
-/**
- * gtk_clipboard_request_text:
- * @clipboard: a #GtkClipboard
- * @callback:  a function to call when the text is received,
- *             or the retrieval fails. (It will always be called
- *             one way or the other.)
- * @user_data: user data to pass to @callback.
- * 
- * Requests the contents of the clipboard as text. When the text is
- * later received, it will be converted to UTF-8 if necessary, and
- * @callback will be called. 
- *
- * The @text parameter to @callback will contain the resulting text if
- * the request succeeded, or %NULL if it failed. This could happen for
- * various reasons, in particular if the clipboard was empty or if the
- * contents of the clipboard could not be converted into text form.
- **/
 void 
 gtk_clipboard_request_text (GtkClipboard                *clipboard,
                            GtkClipboardTextReceivedFunc callback,
@@ -737,26 +642,6 @@ gtk_clipboard_wait_for_rich_text (GtkClipboard  *clipboard,
   return NULL;
 }
 
-/**
- * gtk_clipboard_request_image:
- * @clipboard: a #GtkClipboard
- * @callback:  a function to call when the image is received,
- *             or the retrieval fails. (It will always be called
- *             one way or the other.)
- * @user_data: user data to pass to @callback.
- * 
- * Requests the contents of the clipboard as image. When the image is
- * later received, it will be converted to a #GdkPixbuf, and
- * @callback will be called. 
- *
- * The @pixbuf parameter to @callback will contain the resulting 
- * #GdkPixbuf if the request succeeded, or %NULL if it failed. This 
- * could happen for various reasons, in particular if the clipboard 
- * was empty or if the contents of the clipboard could not be 
- * converted into an image.
- *
- * Since: 2.6
- **/
 void 
 gtk_clipboard_request_image (GtkClipboard                  *clipboard,
                             GtkClipboardImageReceivedFunc  callback,
@@ -770,22 +655,18 @@ gtk_clipboard_request_image (GtkClipboard                  *clipboard,
     g_object_unref (pixbuf);
 }
 
-/**
- * gtk_clipboard_request_targets:
- * @clipboard: a #GtkClipboard
- * @callback:  a function to call when the targets are received,
- *             or the retrieval fails. (It will always be called
- *             one way or the other.)
- * @user_data: user data to pass to @callback.
- * 
- * Requests the contents of the clipboard as list of supported targets. 
- * When the list is later received, @callback will be called. 
- *
- * The @targets parameter to @callback will contain the resulting targets if
- * the request succeeded, or %NULL if it failed.
- *
- * Since: 2.4
- **/
+void 
+gtk_clipboard_request_uris (GtkClipboard                *clipboard,
+                           GtkClipboardURIReceivedFunc  callback,
+                           gpointer                     user_data)
+{
+  gchar **uris = gtk_clipboard_wait_for_uris (clipboard);
+
+  callback (clipboard, uris, user_data);
+
+  g_strfreev (uris);
+}
+
 void 
 gtk_clipboard_request_targets (GtkClipboard                *clipboard,
                               GtkClipboardTargetsReceivedFunc callback,
@@ -799,59 +680,45 @@ gtk_clipboard_request_targets (GtkClipboard                *clipboard,
   callback (clipboard, targets, n_targets, user_data);
 }
 
-
-/**
- * gtk_clipboard_wait_for_contents:
- * @clipboard: a #GtkClipboard
- * @target: an atom representing the form into which the clipboard
- *          owner should convert the selection.
- * 
- * Requests the contents of the clipboard using the given target.
- * This function waits for the data to be received using the main 
- * loop, so events, timeouts, etc, may be dispatched during the wait.
- * 
- * Return value: a newly-allocated #GtkSelectionData object or %NULL
- *               if retrieving the given target failed. If non-%NULL,
- *               this value must be freed with gtk_selection_data_free() 
- *               when you are finished with it.
- **/
 GtkSelectionData *
 gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
                                 GdkAtom       target)
 {
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-  gchar *name;
-  NSData *data;
   GtkSelectionData *selection_data = NULL;
 
+  if (clipboard->change_count < [clipboard->pasteboard changeCount])
+    {
+      clipboard_unset (clipboard);
+      clipboard->change_count = [clipboard->pasteboard changeCount];
+    }
+
   if (target == gdk_atom_intern_static_string ("TARGETS")) 
     {
       NSArray *types = [clipboard->pasteboard types];
-      int i, count;
+      int i, length;
       GList *atom_list, *l;
       GdkAtom *atoms;
 
-      count = [types count];
-      atom_list = _gtk_quartz_pasteboard_types_to_atom_list (types);
+      length = [types count] * sizeof (GdkAtom);
       
-      selection_data = g_new (GtkSelectionData, 1);
+      selection_data = g_slice_new0 (GtkSelectionData);
       selection_data->selection = clipboard->selection;
       selection_data->target = target;
-      selection_data->type = GDK_SELECTION_TYPE_ATOM;
-      selection_data->format = 32;
-      selection_data->length = count * sizeof (GdkAtom);
 
-      atoms = g_malloc (selection_data->length + 1);
-      
+      atoms = g_malloc (length);
+
+      atom_list = _gtk_quartz_pasteboard_types_to_atom_list (types);
       for (l = atom_list, i = 0; l ; l = l->next, i++)
        atoms[i] = GDK_POINTER_TO_ATOM (l->data);
+      g_list_free (atom_list);
 
-      selection_data->data = (guchar *)atoms;
-      selection_data->data[selection_data->length] = '\0';
+      gtk_selection_data_set (selection_data,
+                              GDK_SELECTION_TYPE_ATOM, 32,
+                              (guchar *)atoms, length);
 
       [pool release];
 
-      g_list_free (atom_list);
       return selection_data;
     }
 
@@ -860,25 +727,10 @@ gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
                                                                   clipboard->selection);
 
   [pool release];
+
   return selection_data;
 }
 
-/**
- * gtk_clipboard_wait_for_text:
- * @clipboard: a #GtkClipboard
- * 
- * Requests the contents of the clipboard as text and converts
- * the result to UTF-8 if necessary. This function waits for
- * the data to be received using the main loop, so events,
- * timeouts, etc, may be dispatched during the wait.
- * 
- * Return value: a newly-allocated UTF-8 string which must
- *               be freed with g_free(), or %NULL if retrieving
- *               the selection data failed. (This could happen
- *               for various reasons, in particular if the
- *               clipboard was empty or if the contents of the
- *               clipboard could not be converted into text form.)
- **/
 gchar *
 gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
 {
@@ -895,24 +747,6 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
   return result;
 }
 
-/**
- * gtk_clipboard_wait_for_image:
- * @clipboard: a #GtkClipboard
- * 
- * Requests the contents of the clipboard as image and converts
- * the result to a #GdkPixbuf. This function waits for
- * the data to be received using the main loop, so events,
- * timeouts, etc, may be dispatched during the wait.
- * 
- * Return value: a newly-allocated #GdkPixbuf object which must
- *               be disposed with g_object_unref(), or %NULL if 
- *               retrieving the selection data failed. (This 
- *               could happen for various reasons, in particular 
- *               if the clipboard was empty or if the contents of 
- *               the clipboard could not be converted into an image.)
- *
- * Since: 2.6
- **/
 GdkPixbuf *
 gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
 {
@@ -937,16 +771,25 @@ gtk_clipboard_wait_for_image (GtkClipboard *clipboard)
   return NULL;
 }
 
-/**
- * gtk_clipboard_get_display:
- * @clipboard: a #GtkClipboard
- *
- * Gets the #GdkDisplay associated with @clipboard
- *
- * Return value: the #GdkDisplay associated with @clipboard
- *
- * Since: 2.2
- **/
+gchar **
+gtk_clipboard_wait_for_uris (GtkClipboard *clipboard)
+{
+  GtkSelectionData *data;
+
+  data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("text/uri-list"));
+  if (data)
+    {
+      gchar **uris;
+
+      uris = gtk_selection_data_get_uris (data);
+      gtk_selection_data_free (data);
+
+      return uris;
+    }  
+
+  return NULL;
+}
+
 GdkDisplay *
 gtk_clipboard_get_display (GtkClipboard *clipboard)
 {
@@ -955,22 +798,6 @@ gtk_clipboard_get_display (GtkClipboard *clipboard)
   return clipboard->display;
 }
 
-/**
- * gtk_clipboard_wait_is_text_available:
- * @clipboard: a #GtkClipboard
- * 
- * Test to see if there is text available to be pasted
- * This is done by requesting the TARGETS atom and checking
- * if it contains any of the supported text targets. This function 
- * waits for the data to be received using the main loop, so events, 
- * timeouts, etc, may be dispatched during the wait.
- *
- * This function is a little faster than calling
- * gtk_clipboard_wait_for_text() since it doesn't need to retrieve
- * the actual text.
- * 
- * Return value: %TRUE is there is text available, %FALSE otherwise.
- **/
 gboolean
 gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
 {
@@ -1024,24 +851,23 @@ gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard)
   return result;
 }
 
-/**
- * gtk_clipboard_wait_for_targets
- * @clipboard: a #GtkClipboard
- * @targets: location to store an array of targets. The result
- *           stored here must be freed with g_free().
- * @n_targets: location to store number of items in @targets.
- *
- * Returns a list of targets that are present on the clipboard, or %NULL
- * if there aren't any targets available. The returned list must be 
- * freed with g_free().
- * This function waits for the data to be received using the main 
- * loop, so events, timeouts, etc, may be dispatched during the wait.
- *
- * Return value: %TRUE if any targets are present on the clipboard,
- *               otherwise %FALSE.
- *
- * Since: 2.4
- */
+gboolean
+gtk_clipboard_wait_is_uris_available (GtkClipboard *clipboard)
+{
+  GtkSelectionData *data;
+  gboolean result = FALSE;
+
+  data = gtk_clipboard_wait_for_contents (clipboard, 
+                                         gdk_atom_intern_static_string ("TARGETS"));
+  if (data)
+    {
+      result = gtk_selection_data_targets_include_uri (data);
+      gtk_selection_data_free (data);
+    }
+
+  return result;
+}
+
 gboolean
 gtk_clipboard_wait_for_targets (GtkClipboard  *clipboard, 
                                GdkAtom      **targets,
@@ -1172,22 +998,6 @@ gtk_clipboard_owner_change (GtkClipboard        *clipboard,
     }
 }
 
-/**
- * gtk_clipboard_wait_is_target_available:
- * @clipboard: a #GtkClipboard
- * @target:    A #GdkAtom indicating which target to look for.
- *
- * Checks if a clipboard supports pasting data of a given type. This
- * function can be used to determine if a "Paste" menu item should be
- * insensitive or not.
- *
- * If you want to see if there's text available on the clipboard, use
- * gtk_clipboard_wait_is_text_available () instead.
- *
- * Return value: %TRUE if the target is available, %FALSE otherwise.
- *
- * Since: 2.6
- */
 gboolean
 gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
                                        GdkAtom       target)
@@ -1213,36 +1023,11 @@ gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
   return retval;
 }
 
-/**
- * _gtk_clipboard_handle_event:
- * @event: a owner change event
- * 
- * Emits the ::owner_change signal on the appropriate @clipboard.
- *
- * Since: 2.6
- **/
 void 
 _gtk_clipboard_handle_event (GdkEventOwnerChange *event)
 {
 }
 
-
-/**
- * gtk_clipboard_set_can_store:
- * @clipboard: a #GtkClipboard
- * @targets: array containing information about which forms should be stored
- *           or %NULL to indicate that all forms should be stored.
- * @n_targets: number of elements in @targets
- *
- * Hints that the clipboard data should be stored somewhere when the
- * application exits or when gtk_clipboard_store () is called.
- *
- * This value is reset when the clipboard owner changes.
- * Where the clipboard data is stored is platform dependent,
- * see gdk_display_store_clipboard () for more information.
- * 
- * Since: 2.6
- */
 void
 gtk_clipboard_set_can_store (GtkClipboard         *clipboard,
                             const GtkTargetEntry *targets,
@@ -1251,29 +1036,77 @@ gtk_clipboard_set_can_store (GtkClipboard         *clipboard,
   /* FIXME: Implement */
 }
 
-/**
- * gtk_clipboard_store:
- * @clipboard: a #GtkClipboard
- *
- * Stores the current clipboard data somewhere so that it will stay
- * around after the application has quit.
- *
- * Since: 2.6
- */
 void
 gtk_clipboard_store (GtkClipboard *clipboard)
 {
-  /* FIXME: Implement */
+  int i;
+  int n_targets = 0;
+  GtkTargetEntry *targets;
+
+  g_return_if_fail (GTK_IS_CLIPBOARD (clipboard));
+
+  if (!clipboard->target_list || !clipboard->get_func)
+    return;
+
+  /* We simply store all targets into the OS X clipboard. We should be
+   * using the functions gdk_display_supports_clipboard_persistence() and
+   * gdk_display_store_clipboard(), but since for OS X the clipboard support
+   * was implemented in GTK+ and not through GdkSelections, we do it this
+   * way. Doing this properly could be worthwhile to implement in the future.
+   */
+
+  targets = gtk_target_table_new_from_list (clipboard->target_list,
+                                            &n_targets);
+  for (i = 0; i < n_targets; i++)
+    {
+      GtkSelectionData selection_data;
+
+      /* in each loop iteration, check if the content is still
+       * there, because calling get_func() can do anything to
+       * the clipboard
+       */
+      if (!clipboard->target_list || !clipboard->get_func)
+        break;
+
+      memset (&selection_data, 0, sizeof (GtkSelectionData));
+
+      selection_data.selection = clipboard->selection;
+      selection_data.target = gdk_atom_intern_static_string (targets[i].target);
+      selection_data.display = gdk_display_get_default ();
+      selection_data.length = -1;
+
+      clipboard->get_func (clipboard, &selection_data,
+                           targets[i].info, clipboard->user_data);
+
+      if (selection_data.length >= 0)
+        _gtk_quartz_set_selection_data_for_pasteboard (clipboard->pasteboard,
+                                                       &selection_data);
+
+      g_free (selection_data.data);
+    }
+
+  if (targets)
+    gtk_target_table_free (targets, n_targets);
 }
 
-/* Stores all clipboard selections on all displays, called from
- * gtk_main_quit ().
- */
 void
 _gtk_clipboard_store_all (void)
 {
-  /* FIXME: Implement */
-}
+  GtkClipboard *clipboard;
+  GSList *displays, *list;
+
+  displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
 
-#define __GTK_CLIPBOARD_C__
-#include "gtkaliasdef.c"
+  list = displays;
+  while (list)
+    {
+      GdkDisplay *display = list->data;
+
+      clipboard = clipboard_peek (display, GDK_SELECTION_CLIPBOARD, TRUE);
+
+      if (clipboard)
+        gtk_clipboard_store (clipboard);
+
+      list = list->next;
+    }
+}