]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkselection.c
Switch style of stamp file usage.
[~andy/gtk] / gtk / gtkselection.c
index eb3c652a9b3d5d1b2855976957992f5a452d350e..1974fb1c760de4663930a0470c3a1729da070a64 100644 (file)
@@ -2,16 +2,16 @@
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * 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.
@@ -45,7 +45,7 @@
    to the TARGETS request, though I don't really think so ... */
 
 /*
- * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
@@ -53,7 +53,8 @@
 
 #include <stdarg.h>
 #include <string.h>
-#include "gdkx.h"              /* For gdk_window_lookup() */
+#include "gdk.h"
+
 #include "gtkmain.h"
 #include "gtkselection.h"
 #include "gtksignal.h"
@@ -101,7 +102,6 @@ struct _GtkIncrConversion
 
 struct _GtkIncrInfo
 {
-  GtkWidget *widget;           /* Selection owner */
   GdkWindow *requestor;                /* Requestor window - we create a GdkWindow
                                   so we can receive events */
   GdkAtom    selection;                /* Selection we're sending */
@@ -130,18 +130,21 @@ struct _GtkRetrievalInfo
 };
 
 /* Local Functions */
-static void gtk_selection_init                  (void);
-static gint gtk_selection_incr_timeout          (GtkIncrInfo *info);
-static gint gtk_selection_retrieval_timeout     (GtkRetrievalInfo *info);
-static void gtk_selection_retrieval_report      (GtkRetrievalInfo *info,
-                                                 GdkAtom type, gint format, 
-                                                 guchar *buffer, gint length,
-                                                 guint32 time);
-static void gtk_selection_invoke_handler        (GtkWidget        *widget,
-                                                 GtkSelectionData *data,
-                                                 guint             time);
-static void gtk_selection_default_handler       (GtkWidget       *widget,
-                                                 GtkSelectionData *data);
+static void gtk_selection_init              (void);
+static gint gtk_selection_incr_timeout      (GtkIncrInfo      *info);
+static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info);
+static void gtk_selection_retrieval_report  (GtkRetrievalInfo *info,
+                                            GdkAtom           type,
+                                            gint              format,
+                                            guchar           *buffer,
+                                            gint              length,
+                                            guint32           time);
+static void gtk_selection_invoke_handler    (GtkWidget        *widget,
+                                            GtkSelectionData *data,
+                                            guint             time);
+static void gtk_selection_default_handler   (GtkWidget        *widget,
+                                            GtkSelectionData *data);
+static int  gtk_selection_bytes_per_item    (gint              format);
 
 /* Local Data */
 static gint initialize = TRUE;
@@ -177,12 +180,17 @@ gtk_target_list_new (const GtkTargetEntry *targets,
 void               
 gtk_target_list_ref (GtkTargetList *list)
 {
+  g_return_if_fail (list != NULL);
+
   list->ref_count++;
 }
 
 void               
 gtk_target_list_unref (GtkTargetList *list)
 {
+  g_return_if_fail (list != NULL);
+  g_return_if_fail (list->ref_count > 0);
+
   list->ref_count--;
   if (list->ref_count == 0)
     {
@@ -253,7 +261,7 @@ gtk_target_list_remove (GtkTargetList *list,
        {
          g_free (pair);
 
-         list->list = g_list_remove (list->list, tmp_list);
+         list->list = g_list_remove_link (list->list, tmp_list);
          g_list_free_1 (tmp_list);
 
          return;
@@ -296,7 +304,7 @@ gtk_target_list_find (GtkTargetList *list,
  *   results:
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_owner_set (GtkWidget *widget,
                         GdkAtom    selection,
                         guint32    time)
@@ -305,34 +313,26 @@ gtk_selection_owner_set (GtkWidget *widget,
   GtkWidget *old_owner;
   GtkSelectionInfo *selection_info = NULL;
   GdkWindow *window;
+
+  g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
   
   if (widget == NULL)
     window = NULL;
   else
-    {
-      if (!GTK_WIDGET_REALIZED (widget))
-       gtk_widget_realize (widget);
-      
-      window = widget->window;
-    }
-  
+    window = widget->window;
+
   tmp_list = current_selections;
   while (tmp_list)
     {
-      selection_info = (GtkSelectionInfo *)tmp_list->data;
-      
-      if (selection_info->selection == selection)
-       break;
+      if (((GtkSelectionInfo *)tmp_list->data)->selection == selection)
+       {
+         selection_info = tmp_list->data;
+         break;
+       }
       
       tmp_list = tmp_list->next;
     }
   
-  if (tmp_list == NULL)
-    selection_info = NULL;
-  else
-    if (selection_info->widget == widget)
-      return TRUE;
-  
   if (gdk_selection_owner_set (window, selection, time, TRUE))
     {
       old_owner = NULL;
@@ -356,8 +356,8 @@ gtk_selection_owner_set (GtkWidget *widget,
              selection_info->selection = selection;
              selection_info->widget = widget;
              selection_info->time = time;
-             current_selections = g_list_append (current_selections, 
-                                                 selection_info);
+             current_selections = g_list_prepend (current_selections, 
+                                                  selection_info);
            }
          else
            {
@@ -367,9 +367,9 @@ gtk_selection_owner_set (GtkWidget *widget,
            }
        }
       /* If another widget in the application lost the selection,
-       *  send it a GDK_SELECTION_CLEAR event, unless we're setting
-       *  the owner to None, in which case an event will be sent */
-      if (old_owner && (widget != NULL))
+       *  send it a GDK_SELECTION_CLEAR event.
+       */
+      if (old_owner && old_owner != widget)
        {
          GdkEventSelection event;
          
@@ -459,6 +459,43 @@ gtk_selection_target_list_remove (GtkWidget    *widget)
   gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, NULL);
 }
 
+/**
+ * gtk_selection_clear_targets:
+ * @widget:    a #GtkWidget
+ * @selection: an atom representing a selection
+ *
+ * Remove all targets registered for the given selection for the
+ * widget.
+ **/
+void 
+gtk_selection_clear_targets (GtkWidget *widget,
+                            GdkAtom    selection)
+{
+  GtkSelectionTargetList *sellist;
+  GList *tmp_list;
+  GList *lists;
+
+  lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
+  
+  tmp_list = lists;
+  while (tmp_list)
+    {
+      sellist = tmp_list->data;
+      if (sellist->selection == selection)
+       {
+         lists = g_list_delete_link (lists, tmp_list);
+         gtk_target_list_unref (sellist->list);
+         g_free (sellist);
+
+         break;
+       }
+      
+      tmp_list = tmp_list->next;
+    }
+  
+  gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, lists);
+}
+
 void 
 gtk_selection_add_target (GtkWidget        *widget, 
                          GdkAtom            selection,
@@ -488,6 +525,7 @@ gtk_selection_add_targets (GtkWidget            *widget,
   gtk_target_list_add_table (list, targets, ntargets);
 }
 
+
 /*************************************************************
  * gtk_selection_remove_all:
  *     Removes all handlers and unsets ownership of all 
@@ -508,19 +546,6 @@ gtk_selection_remove_all (GtkWidget *widget)
   
   /* Remove pending requests/incrs for this widget */
   
-  tmp_list = current_incrs;
-  while (tmp_list)
-    {
-      next = tmp_list->next;
-      if (((GtkIncrInfo *)tmp_list->data)->widget == widget)
-       {
-         current_incrs = g_list_remove_link (current_incrs, tmp_list);
-         /* structure will be freed in timeout */
-         g_list_free (tmp_list);
-       }
-      tmp_list = next;
-    }
-  
   tmp_list = current_retrievals;
   while (tmp_list)
     {
@@ -579,7 +604,7 @@ gtk_selection_remove_all (GtkWidget *widget)
  *     this widget). 
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_convert (GtkWidget *widget, 
                       GdkAtom    selection, 
                       GdkAtom    target,
@@ -683,7 +708,7 @@ void
 gtk_selection_data_set (GtkSelectionData *selection_data,
                        GdkAtom           type,
                        gint              format,
-                       guchar           *data,
+                       const guchar     *data,
                        gint              length)
 {
   if (selection_data->data)
@@ -711,6 +736,213 @@ gtk_selection_data_set (GtkSelectionData *selection_data,
   selection_data->length = length;
 }
 
+static GdkAtom utf8_atom;
+static GdkAtom text_atom;
+static GdkAtom ctext_atom;
+
+static void 
+init_atoms (void)
+{
+  if (!utf8_atom)
+    {
+      utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
+      text_atom = gdk_atom_intern ("TEXT", FALSE);
+      ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
+    }
+}
+
+/**
+ * gtk_selection_data_set_text:
+ * @selection_data: a #GtkSelectionData
+ * @str: a UTF-8 string
+ * @len: the length of @str, or -1 if @str is nul-terminated.
+ * 
+ * Sets the contents of the selection from a UTF-8 encoded string.
+ * The string is converted to the form determined by
+ * @selection_data->target.
+ * 
+ * Return value: %TRUE if the selection was successfully set,
+ *   otherwise %FALSE.
+ **/
+gboolean
+gtk_selection_data_set_text (GtkSelectionData     *selection_data,
+                            const gchar          *str,
+                            gint                  len)
+{
+  gboolean result = FALSE;
+  
+  if (len < 0)
+    len = strlen (str);
+  
+  init_atoms ();
+
+  if (selection_data->target == utf8_atom)
+    {
+      gtk_selection_data_set (selection_data,
+                             utf8_atom,
+                             8, (guchar *)str, len);
+      result = TRUE;
+    }
+  else if (selection_data->target == GDK_TARGET_STRING)
+    {
+      gchar *tmp = g_strndup (str, len);
+      gchar *latin1 = gdk_utf8_to_string_target (tmp);
+      g_free (tmp);
+
+      if (latin1)
+       {
+         gtk_selection_data_set (selection_data,
+                                 GDK_SELECTION_TYPE_STRING,
+                                 8, latin1, strlen (latin1));
+         g_free (latin1);
+         
+         result = TRUE;
+       }
+
+    }
+  else if (selection_data->target == ctext_atom ||
+          selection_data->target == text_atom)
+    {
+      gchar *tmp;
+      guchar *text;
+      GdkAtom encoding;
+      gint format;
+      gint new_length;
+
+      tmp = g_strndup (str, len);
+      if (gdk_utf8_to_compound_text (tmp, &encoding, &format, &text, &new_length))
+       {
+         gtk_selection_data_set (selection_data, encoding, format, text, new_length);
+         gdk_free_compound_text (text);
+
+         result = TRUE;
+       }
+
+      g_free (tmp);
+    }
+  
+  return result;
+}
+
+/**
+ * gtk_selection_data_get_text:
+ * @selection_data: a #GtkSelectionData
+ * 
+ * Gets the contents of the selection data as a UTF-8 string.
+ * 
+ * Return value: if the selection data contained a recognized
+ *   text type and it could be converted to UTF-8, a newly allocated
+ *   string containing the converted text, otherwise %NULL.
+ *   If the result is non-%NULL it must be freed with g_free().
+ **/
+guchar *
+gtk_selection_data_get_text (GtkSelectionData *selection_data)
+{
+  guchar *result = NULL;
+
+  init_atoms ();
+  
+  if (selection_data->length >= 0 &&
+      (selection_data->type == GDK_TARGET_STRING ||
+       selection_data->type == ctext_atom ||
+       selection_data->type == utf8_atom))
+    {
+      gchar **list;
+      gint i;
+      gint count = gdk_text_property_to_utf8_list (selection_data->type,
+                                                  selection_data->format, 
+                                                  selection_data->data,
+                                                  selection_data->length,
+                                                  &list);
+      if (count > 0)
+       result = list[0];
+
+      for (i = 1; i < count; i++)
+       g_free (list[i]);
+      g_free (list);
+    }
+
+  return result;
+}
+
+/**
+ * gtk_selection_data_get_targets:
+ * @selection_data: a #GtkSelectionData object
+ * @targets: location to store an array of targets. The result
+ *           stored here must be freed with g_free().
+ * @n_atoms: location to store number of items in @targets.
+ * 
+ * Gets the contents of @selection_data as an array of targets.
+ * This can be used to interpret the results of getting
+ * the standard TARGETS target that is always supplied for
+ * any selection.
+ * 
+ * Return value: %TRUE if @selection_data contains a valid
+ *    array of targets, otherwise %FALSE.
+ **/
+gboolean
+gtk_selection_data_get_targets (GtkSelectionData  *selection_data,
+                               GdkAtom          **targets,
+                               gint              *n_atoms)
+{
+  if (selection_data->length >= 0 &&
+      selection_data->format == 32 &&
+      selection_data->type == GDK_SELECTION_TYPE_ATOM)
+    {
+      if (targets)
+       *targets = g_memdup (selection_data->data, selection_data->length);
+      if (n_atoms)
+       *n_atoms = selection_data->length / sizeof (GdkAtom);
+
+      return TRUE;
+    }
+  else
+    {
+      if (targets)
+       *targets = NULL;
+      if (n_atoms)
+       *n_atoms = -1;
+
+      return FALSE;
+    }
+}
+
+/**
+ * gtk_selection_data_targets_include_text:
+ * @selection_data: a #GtkSelectionData object
+ * 
+ * Given a #GtkSelectionData object holding a list of targets,
+ * determines if any of the targets in @targets can be used to
+ * provide text.
+ * 
+ * Return value: %TRUE if @selection_data holds a list of targets,
+ *   and a suitable target for text is included, otherwise %FALSE.
+ **/
+gboolean
+gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
+{
+  GdkAtom *targets;
+  gint n_targets;
+  gint i;
+  gboolean result = FALSE;
+
+  if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
+    {
+      for (i=0; i < n_targets; i++)
+       {
+         if (targets[i] == gdk_atom_intern ("STRING", FALSE) ||
+             targets[i] == gdk_atom_intern ("TEXT", FALSE) ||
+             targets[i] == gdk_atom_intern ("COMPOUND_TEXT", FALSE) ||
+             targets[i] == gdk_atom_intern ("UTF8_STRING", FALSE))
+           result = TRUE;
+       }
+
+      g_free (targets);
+    }
+
+  return result;
+}
+         
 /*************************************************************
  * gtk_selection_init:
  *     Initialize local variables
@@ -737,17 +969,14 @@ gtk_selection_init (void)
  *   results:
  *************************************************************/
 
-gint
-gtk_selection_clear (GtkWidget *widget,
+gboolean
+gtk_selection_clear (GtkWidget         *widget,
                     GdkEventSelection *event)
 {
-  /* FIXME: there can be a problem if we change the selection
-     via gtk_selection_owner_set after another client claims 
-     the selection, but before we get the notification event.
-     Tk filters based on serial #'s, which aren't retained by
-     GTK. Filtering based on time's will be inherently 
-     somewhat unreliable. */
-  
+  /* Note that we filter clear events in gdkselection-x11.c, so
+   * that we only will get here if the clear event actually
+   * represents a change that we didn't do ourself.
+   */
   GList *tmp_list;
   GtkSelectionInfo *selection_info = NULL;
   
@@ -765,16 +994,9 @@ gtk_selection_clear (GtkWidget *widget,
   
   if (tmp_list)
     {
-      if (selection_info->time > event->time)
-       return FALSE;           /* return FALSE to indicate that
-                                * the selection was out of date,
-                                * and this clear should be ignored */
-      else
-       {
-         current_selections = g_list_remove_link (current_selections, tmp_list);
-         g_list_free (tmp_list);
-         g_free (selection_info);
-       }
+      current_selections = g_list_remove_link (current_selections, tmp_list);
+      g_list_free (tmp_list);
+      g_free (selection_info);
     }
   
   return TRUE;
@@ -790,7 +1012,7 @@ gtk_selection_clear (GtkWidget *widget,
  *   results:
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_request (GtkWidget *widget,
                       GdkEventSelection *event)
 {
@@ -819,14 +1041,14 @@ gtk_selection_request (GtkWidget *widget,
   if (tmp_list == NULL)
     return FALSE;
   
-  info = g_new(GtkIncrInfo, 1);
+  info = g_new (GtkIncrInfo, 1);
+
+  g_object_ref (widget);
   
-  info->widget = widget;
   info->selection = event->selection;
   info->num_incrs = 0;
   
   /* Create GdkWindow structure for the requestor */
-  
   info->requestor = gdk_window_lookup (event->requestor);
   if (!info->requestor)
     info->requestor = gdk_window_foreign_new (event->requestor);
@@ -840,6 +1062,8 @@ gtk_selection_request (GtkWidget *widget,
       gint     length;
       
       mult_atoms = NULL;
+      
+      gdk_error_trap_push ();
       if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */
                             0, GTK_SELECTION_MAX_SIZE, FALSE,
                             &type, &format, &length, &mult_atoms))
@@ -850,6 +1074,7 @@ gtk_selection_request (GtkWidget *widget,
          g_free (info);
          return TRUE;
        }
+      gdk_error_trap_pop ();
       
       info->num_conversions = length / (2*sizeof (GdkAtom));
       info->conversions = g_new (GtkIncrConversion, info->num_conversions);
@@ -874,7 +1099,7 @@ gtk_selection_request (GtkWidget *widget,
   for (i=0; i<info->num_conversions; i++)
     {
       GtkSelectionData data;
-      gint items;
+      glong items;
       
       data.selection = event->selection;
       data.target = info->conversions[i].target;
@@ -884,7 +1109,7 @@ gtk_selection_request (GtkWidget *widget,
 #ifdef DEBUG_SELECTION
       g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)",
                 event->selection, info->conversions[i].target,
-                gdk_atom_name(info->conversions[i].target),
+                gdk_atom_name (info->conversions[i].target),
                 event->requestor, event->property);
 #endif
       
@@ -899,7 +1124,7 @@ gtk_selection_request (GtkWidget *widget,
       
       g_return_val_if_fail ((data.format >= 8) && (data.format % 8 == 0), FALSE);
       
-      items = (data.length + data.format/8 - 1) / (data.format/8);
+      items = data.length / gtk_selection_bytes_per_item (data.format);
       
       if (data.length > GTK_SELECTION_MAX_SIZE)
        {
@@ -912,7 +1137,7 @@ gtk_selection_request (GtkWidget *widget,
          gdk_property_change (info->requestor, 
                               info->conversions[i].property,
                               gtk_selection_atoms[INCR],
-                              8*sizeof (GdkAtom),
+                              32,
                               GDK_PROP_MODE_REPLACE,
                               (guchar *)&items, 1);
        }
@@ -955,20 +1180,32 @@ gtk_selection_request (GtkWidget *widget,
   if (event->target == gtk_selection_atoms[MULTIPLE])
     {
       gdk_property_change (info->requestor, event->property,
-                          GDK_SELECTION_TYPE_ATOM, 8*sizeof(GdkAtom)
+                          gdk_atom_intern ("ATOM_PAIR", FALSE), 32
                           GDK_PROP_MODE_REPLACE,
                           mult_atoms, 2*info->num_conversions);
       g_free (mult_atoms);
     }
-  
-  gdk_selection_send_notify (event->requestor, event->selection, event->target,
-                            event->property, event->time);
-  
+
+  if (info->num_conversions == 1 &&
+      info->conversions[0].property == GDK_NONE)
+    {
+      /* Reject the entire conversion */
+      gdk_selection_send_notify (event->requestor, event->selection, 
+                                event->target, GDK_NONE, event->time);
+    }
+  else
+    {
+      gdk_selection_send_notify (event->requestor, event->selection, 
+                                event->target, event->property, event->time);
+    }
+
   if (info->num_incrs == 0)
     {
       g_free (info->conversions);
       g_free (info);
     }
+
+  g_object_unref (widget);
   
   return TRUE;
 }
@@ -988,7 +1225,7 @@ gtk_selection_request (GtkWidget *widget,
  *   results:
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_incr_event (GdkWindow       *window,
                          GdkEventProperty *event)
 {
@@ -1026,6 +1263,8 @@ gtk_selection_incr_event (GdkWindow          *window,
       if (info->conversions[i].property == event->atom &&
          info->conversions[i].offset != -1)
        {
+         int bytes_per_item;
+         
          info->idle_time = 0;
          
          if (info->conversions[i].offset == -2) /* only the last 0-length
@@ -1054,13 +1293,14 @@ gtk_selection_incr_event (GdkWindow        *window,
                     num_bytes, info->conversions[i].offset, 
                     GDK_WINDOW_XWINDOW(info->requestor), event->atom);
 #endif
+
+         bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format);
          gdk_property_change (info->requestor, event->atom,
                               info->conversions[i].data.type,
                               info->conversions[i].data.format,
                               GDK_PROP_MODE_REPLACE,
-                              buffer, 
-                              (num_bytes + info->conversions[i].data.format/8 - 1) / 
-                              (info->conversions[i].data.format/8));
+                              buffer,
+                              num_bytes / bytes_per_item);
          
          if (info->conversions[i].offset == -2)
            {
@@ -1159,13 +1399,13 @@ gtk_selection_incr_timeout (GtkIncrInfo *info)
  *     was event handled?
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_notify (GtkWidget               *widget,
                      GdkEventSelection *event)
 {
   GList *tmp_list;
   GtkRetrievalInfo *info = NULL;
-  guchar  *buffer;
+  guchar  *buffer = NULL;
   gint length;
   GdkAtom type;
   gint   format;
@@ -1186,8 +1426,14 @@ gtk_selection_notify (GtkWidget         *widget,
   
   if (!tmp_list)               /* no retrieval in progress */
     return FALSE;
+
+  if (event->property != GDK_NONE)
+    length = gdk_selection_property_get (widget->window, &buffer, 
+                                        &type, &format);
+  else
+    length = 0; /* silence gcc */
   
-  if (event->property == GDK_NONE)
+  if (event->property == GDK_NONE || buffer == NULL)
     {
       current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
       g_list_free (tmp_list);
@@ -1198,9 +1444,6 @@ gtk_selection_notify (GtkWidget          *widget,
       return TRUE;
     }
   
-  length = gdk_selection_property_get (widget->window, &buffer, 
-                                      &type, &format);
-  
   if (type == gtk_selection_atoms[INCR])
     {
       /* The remainder of the selection will come through PropertyNotify
@@ -1245,7 +1488,7 @@ gtk_selection_notify (GtkWidget          *widget,
  *     was event handled?
  *************************************************************/
 
-gint
+gboolean
 gtk_selection_property_notify (GtkWidget       *widget,
                               GdkEventProperty *event)
 {
@@ -1259,8 +1502,10 @@ gtk_selection_property_notify (GtkWidget *widget,
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
+#if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11)
   if ((event->state != GDK_PROPERTY_NEW_VALUE) ||  /* property was deleted */
-      (event->atom != gdk_selection_property)) /* not the right property */
+      (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */
+#endif
     return FALSE;
   
 #ifdef DEBUG_SELECTION
@@ -1489,11 +1734,13 @@ gtk_selection_default_handler (GtkWidget        *widget,
          if ((selection_info->widget == widget) &&
              (selection_info->selection == data->selection))
            {
+             gulong time = selection_info->time;
+
              gtk_selection_data_set (data,
                                      GDK_SELECTION_TYPE_INTEGER,
-                                     sizeof (guint32)*8,
-                                     (guchar *)&selection_info->time,
-                                     sizeof (guint32));
+                                     32,
+                                     (guchar *)&time,
+                                     sizeof (time));
              return;
            }
          
@@ -1516,7 +1763,7 @@ gtk_selection_default_handler (GtkWidget  *widget,
       count = g_list_length (target_list->list) + 3;
       
       data->type = GDK_SELECTION_TYPE_ATOM;
-      data->format = 8*sizeof (GdkAtom);
+      data->format = 32;
       data->length = count * sizeof (GdkAtom);
       
       p = g_new (GdkAtom, count);
@@ -1542,15 +1789,21 @@ gtk_selection_default_handler (GtkWidget        *widget,
 }
 
 
-GtkSelectioData*
-gtk_selection_data_copy (GtkSelectionData *data)
+GtkSelectionData*
+gtk_selection_data_copy (GtkSelectionData *selection_data)
 {
   GtkSelectionData *new_data;
   
-  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (selection_data != NULL, NULL);
   
   new_data = g_new (GtkSelectionData, 1);
-  *new_data = *data;
+  *new_data = *selection_data;
+
+  if (selection_data->data)
+    {
+      new_data->data = g_malloc (selection_data->length + 1);
+      memcpy (new_data->data, selection_data->data, selection_data->length + 1);
+    }
   
   return new_data;
 }
@@ -1560,5 +1813,41 @@ gtk_selection_data_free (GtkSelectionData *data)
 {
   g_return_if_fail (data != NULL);
   
+  if (data->data)
+    g_free (data->data);
+  
   g_free (data);
 }
+
+GType
+gtk_selection_data_get_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("GtkTypeSelectionData",
+                                            (GBoxedCopyFunc) gtk_selection_data_copy,
+                                            (GBoxedFreeFunc) gtk_selection_data_free);
+
+  return our_type;
+}
+
+static int 
+gtk_selection_bytes_per_item (gint format)
+{
+  switch (format)
+    {
+    case 8:
+      return sizeof (char);
+      break;
+    case 16:
+      return sizeof (short);
+      break;
+    case 32:
+      return sizeof (long);
+      break;
+    default:
+      g_assert_not_reached();
+    }
+  return 0;
+}