* 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
* 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
}
}
+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
const gchar *str,
gint len)
{
- gboolean result = FALSE;
-
if (len < 0)
len = strlen (str);
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;
}
/**
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;
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,
#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);
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;
GtkIncrInfo *info = NULL;
gint num_bytes;
guchar *buffer;
+ gulong selection_max_size;
int i;
#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)
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;
info->conversions[i].offset = -1;
}
}
- break;
}
/* Check if we're finished with all the targets */
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];