]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkselection.c
Make the chunk size for incremental transfers depend on the maximal
[~andy/gtk] / gtk / gtkselection.c
index 6d976896ead97371e6f8ecfda7d1b3984cbc52b4..d6f3bc7b8747b64933aecaecc6ab6fc250a2cb72 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-/* This file implements most of the work of the ICCM selection protocol.
+/* This file implements most of the work of the ICCCM selection protocol.
  * The code was written after an intensive study of the equivalent part
  * of John Ousterhout's Tk toolkit, and does many things in much the 
  * same way.
  *
- * The one thing in the ICCM that isn't fully supported here (or in Tk)
+ * The one thing in the ICCCM that isn't fully supported here (or in Tk)
  * is side effects targets. For these to be handled properly, MULTIPLE
  * targets need to be done in the order specified. This cannot be
  * guaranteed with the way we do things, since if we are doing INCR
@@ -51,6 +51,7 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include <config.h>
 #include <stdarg.h>
 #include <string.h>
 #include "gdk.h"
 #include "x11/gdkx.h"
 #endif
 
-/* #define DEBUG_SELECTION */
+#define DEBUG_SELECTION
 
 /* Maximum size of a sent chunk, in bytes. Also the default size of
    our buffers */
 #ifdef GDK_WINDOWING_WIN32
 /* No chunks on Win32 */
-#define GTK_SELECTION_MAX_SIZE G_MAXINT
+#define GTK_SELECTION_MAX_SIZE(display) G_MAXINT
 #else
-#define GTK_SELECTION_MAX_SIZE 4000
+#define GTK_SELECTION_MAX_SIZE(display)                                 \
+  MIN(262144,                                                           \
+      XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
+       ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100         \
+       : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
 #endif
 
 #define IDLE_ABORT_TIME 300
@@ -813,6 +818,55 @@ init_atoms (void)
     }
 }
 
+static gboolean
+selection_set_string (GtkSelectionData *selection_data,
+                     const gchar      *str,
+                     gint              len)
+{
+  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);
+      
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+static gboolean
+selection_set_compound_text (GtkSelectionData *selection_data,
+                            const gchar      *str,
+                            gint              len)
+{
+  gchar *tmp;
+  guchar *text;
+  GdkAtom encoding;
+  gint format;
+  gint new_length;
+  gboolean result = FALSE;
+  
+  tmp = g_strndup (str, len);
+  if (gdk_utf8_to_compound_text_for_display (selection_data->display, 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_set_text:
  * @selection_data: a #GtkSelectionData
@@ -831,8 +885,6 @@ gtk_selection_data_set_text (GtkSelectionData     *selection_data,
                             const gchar          *str,
                             gint                  len)
 {
-  gboolean result = FALSE;
-  
   if (len < 0)
     len = strlen (str);
   
@@ -843,48 +895,22 @@ gtk_selection_data_set_text (GtkSelectionData     *selection_data,
       gtk_selection_data_set (selection_data,
                              utf8_atom,
                              8, (guchar *)str, len);
-      result = TRUE;
+      return 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;
-       }
-
+      return selection_set_string (selection_data, str, len);
     }
   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_for_display (selection_data->display, 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);
+      if (selection_set_compound_text (selection_data, str, len))
+       return TRUE;
+      else if (selection_data->target == text_atom)
+       return selection_set_string (selection_data, str, len);
     }
-  
-  return result;
+
+  return FALSE;
 }
 
 /**
@@ -1093,10 +1119,16 @@ _gtk_selection_request (GtkWidget *widget,
   GtkIncrInfo *info;
   GList *tmp_list;
   int i;
-  
+  gulong selection_max_size;
+
   if (initialize)
     gtk_selection_init ();
   
+  g_message ("max request sizes %ld %ld\n", 
+            XMaxRequestSize(GDK_DISPLAY_XDISPLAY(display)),
+            XExtendedMaxRequestSize(GDK_DISPLAY_XDISPLAY(display)));
+  selection_max_size = GTK_SELECTION_MAX_SIZE (display);
+
   /* Check if we own selection */
   
   tmp_list = current_selections;
@@ -1141,8 +1173,8 @@ _gtk_selection_request (GtkWidget *widget,
       mult_atoms = NULL;
       
       gdk_error_trap_push ();
-      if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */
-                            0, GTK_SELECTION_MAX_SIZE, FALSE,
+      if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
+                            0, selection_max_size, FALSE,
                             &type, &format, &length, &mult_atoms))
        {
          gdk_selection_send_notify_for_display (display,
@@ -1212,9 +1244,10 @@ _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,
+                event->selection, 
+                info->conversions[i].target,
                 gdk_atom_name (info->conversions[i].target),
-                event->requestor, event->property);
+                event->requestor, info->conversions[i].property);
 #endif
       
       gtk_selection_invoke_handler (widget, &data, event->time);
@@ -1229,9 +1262,13 @@ _gtk_selection_request (GtkWidget *widget,
       
       items = data.length / gtk_selection_bytes_per_item (data.format);
       
-      if (data.length > GTK_SELECTION_MAX_SIZE)
+      if (data.length > selection_max_size)
        {
          /* Sending via INCR */
+#ifdef DEBUG_SELECTION
+         g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n",
+                    data.length, selection_max_size);
+#endif
          
          info->conversions[i].offset = 0;
          info->conversions[i].data = data;
@@ -1351,6 +1388,7 @@ _gtk_selection_incr_event (GdkWindow         *window,
   GtkIncrInfo *info = NULL;
   gint num_bytes;
   guchar *buffer;
+  gulong selection_max_size;
   
   int i;
   
@@ -1360,7 +1398,9 @@ _gtk_selection_incr_event (GdkWindow         *window,
 #ifdef DEBUG_SELECTION
   g_message ("PropertyDelete, property %ld", event->atom);
 #endif
-  
+
+  selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window));  
+
   /* Now find the appropriate ongoing INCR */
   tmp_list = current_incrs;
   while (tmp_list)
@@ -1398,10 +1438,10 @@ _gtk_selection_incr_event (GdkWindow       *window,
              buffer = info->conversions[i].data.data + 
                info->conversions[i].offset;
              
-             if (num_bytes > GTK_SELECTION_MAX_SIZE)
+             if (num_bytes > selection_max_size)
                {
-                 num_bytes = GTK_SELECTION_MAX_SIZE;
-                 info->conversions[i].offset += GTK_SELECTION_MAX_SIZE;
+                 num_bytes = selection_max_size;
+                 info->conversions[i].offset += selection_max_size;
                }
              else
                info->conversions[i].offset = -2;
@@ -1432,7 +1472,6 @@ _gtk_selection_incr_event (GdkWindow         *window,
              info->conversions[i].offset = -1;
            }
        }
-      break;
     }
   
   /* Check if we're finished with all the targets */
@@ -1884,9 +1923,12 @@ gtk_selection_default_handler (GtkWidget *widget,
       data->type = GDK_SELECTION_TYPE_ATOM;
       data->format = 32;
       data->length = count * sizeof (GdkAtom);
-      
-      p = g_new (GdkAtom, count);
+
+      /* selection data is always terminated by a trailing \0
+       */
+      p = g_malloc (data->length + 1);
       data->data = (guchar *)p;
+      data->data[data->length] = '\0';
       
       *p++ = gtk_selection_atoms[TIMESTAMP];
       *p++ = gtk_selection_atoms[TARGETS];