[gtk+] x11: Refactor code
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] x11: Refactor code
- Date: Wed, 13 Dec 2017 00:13:55 +0000 (UTC)
commit 5df527edaf47b3cc1e85c6a0d537bf94dd35db93
Author: Benjamin Otte <otte redhat com>
Date: Tue Dec 12 15:25:34 2017 +0100
x11: Refactor code
This is in preparation for DND.
It moves a lot of code from gdkclipboard-x11.c to
gdkselectionoutputstream-x11.c to untangle it from GdkX11Clipboard
usage.
gdk/x11/gdkclipboard-x11.c | 347 ++---------------------
gdk/x11/gdkclipboard-x11.h | 4 +
gdk/x11/gdkselectionoutputstream-x11.c | 495 ++++++++++++++++++++++++++++----
gdk/x11/gdkselectionoutputstream-x11.h | 28 +--
4 files changed, 476 insertions(+), 398 deletions(-)
---
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
index 817792e..78edb2a 100644
--- a/gdk/x11/gdkclipboard-x11.c
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -92,12 +92,12 @@ gdk_x11_clipboard_default_output_done (GObject *clipboard,
}
static void
-gdk_x11_clipboard_default_output_handler (GdkX11Clipboard *cb,
- const char *target,
- GOutputStream *stream)
+gdk_x11_clipboard_default_output_handler (GOutputStream *stream,
+ const char *mime_type,
+ gpointer user_data)
{
- gdk_clipboard_write_async (GDK_CLIPBOARD (cb),
- g_intern_string (target),
+ gdk_clipboard_write_async (GDK_CLIPBOARD (user_data),
+ mime_type,
stream,
G_PRIORITY_DEFAULT,
NULL,
@@ -106,108 +106,6 @@ gdk_x11_clipboard_default_output_handler (GdkX11Clipboard *cb,
g_object_unref (stream);
}
-static void
-handle_targets_done (GObject *stream,
- GAsyncResult *result,
- gpointer user_data)
-{
- GError *error = NULL;
- gsize bytes_written;
-
- if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, &bytes_written, &error))
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("---: failed to send targets after %zu bytes: %s\n",
- bytes_written, error->message));
- g_error_free (error);
- }
-
- g_free (user_data);
-}
-
-static Atom *
-gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
- gboolean include_special,
- GdkContentFormats *formats,
- gsize *n_atoms);
-
-static void
-handle_targets (GdkX11Clipboard *cb,
- const char *target,
- const char *encoding,
- int format,
- GOutputStream *stream)
-{
- GdkClipboard *clipboard = GDK_CLIPBOARD (cb);
- Atom *atoms;
- gsize n_atoms;
-
- atoms = gdk_x11_clipboard_formats_to_atoms (gdk_clipboard_get_display (clipboard),
- TRUE,
- gdk_clipboard_get_formats (clipboard),
- &n_atoms);
- print_atoms (cb, "sending targets", atoms, n_atoms);
- g_output_stream_write_all_async (stream,
- atoms,
- n_atoms * sizeof (Atom),
- G_PRIORITY_DEFAULT,
- NULL,
- handle_targets_done,
- atoms);
- g_object_unref (stream);
-}
-
-static void
-handle_timestamp_done (GObject *stream,
- GAsyncResult *result,
- gpointer user_data)
-{
- GError *error = NULL;
- gsize bytes_written;
-
- if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, &bytes_written, &error))
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("---: failed to send timestamp after %zu bytes: %s\n",
- bytes_written, error->message));
- g_error_free (error);
- }
-
- g_slice_free (gulong, user_data);
-}
-
-static void
-handle_timestamp (GdkX11Clipboard *cb,
- const char *target,
- const char *encoding,
- int format,
- GOutputStream *stream)
-{
- gulong *timestamp;
-
- timestamp = g_slice_new (gulong);
- *timestamp = cb->timestamp;
-
- g_output_stream_write_all_async (stream,
- timestamp,
- sizeof (gulong),
- G_PRIORITY_DEFAULT,
- NULL,
- handle_timestamp_done,
- timestamp);
- g_object_unref (stream);
-}
-
-static void
-handle_save_targets (GdkX11Clipboard *cb,
- const char *target,
- const char *encoding,
- int format,
- GOutputStream *stream)
-{
- /* Don't do anything */
-
- g_object_unref (stream);
-}
-
static GInputStream *
text_list_convert (GdkX11Clipboard *cb,
GInputStream *stream,
@@ -228,37 +126,6 @@ text_list_convert (GdkX11Clipboard *cb,
return converter_stream;
}
-static void
-handle_text_list (GdkX11Clipboard *cb,
- const char *target,
- const char *encoding,
- int format,
- GOutputStream *stream)
-{
- GOutputStream *converter_stream;
- GConverter *converter;
-
- converter = gdk_x11_text_list_converter_to_utf8_new (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
- encoding,
- format);
- converter_stream = g_converter_output_stream_new (stream, converter);
-
- g_object_unref (converter);
- g_object_unref (stream);
-
- gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", converter_stream);
-}
-
-static void
-handle_utf8 (GdkX11Clipboard *cb,
- const char *target,
- const char *encoding,
- int format,
- GOutputStream *stream)
-{
- gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", stream);
-}
-
static GInputStream *
no_convert (GdkX11Clipboard *cb,
GInputStream *stream,
@@ -268,23 +135,20 @@ no_convert (GdkX11Clipboard *cb,
return stream;
}
-typedef void (* MimeTypeHandleFunc) (GdkX11Clipboard *, const char *, const char *, int, GOutputStream *);
-
static const struct {
const char *x_target;
const char *mime_type;
GInputStream * (* convert) (GdkX11Clipboard *, GInputStream *, const char *, int);
const char *type;
gint format;
- MimeTypeHandleFunc handler;
} special_targets[] = {
- { "UTF8_STRING", "text/plain;charset=utf-8", no_convert, "UTF8_STRING", 8, handle_utf8 },
- { "COMPOUND_TEXT", "text/plain;charset=utf-8", text_list_convert, "COMPOUND_TEXT", 8, handle_text_list },
- { "TEXT", "text/plain;charset=utf-8", text_list_convert, "STRING", 8, handle_text_list },
- { "STRING", "text/plain;charset=utf-8", text_list_convert, "STRING", 8, handle_text_list },
- { "TARGETS", NULL, NULL, "ATOM", 32, handle_targets },
- { "TIMESTAMP", NULL, NULL, "INTEGER", 32, handle_timestamp },
- { "SAVE_TARGETS", NULL, NULL, "NULL", 32, handle_save_targets
}
+ { "UTF8_STRING", "text/plain;charset=utf-8", no_convert, "UTF8_STRING", 8 },
+ { "COMPOUND_TEXT", "text/plain;charset=utf-8", text_list_convert, "COMPOUND_TEXT", 8 },
+ { "TEXT", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
+ { "STRING", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
+ { "TARGETS", NULL, NULL, "ATOM", 32 },
+ { "TIMESTAMP", NULL, NULL, "INTEGER", 32 },
+ { "SAVE_TARGETS", NULL, NULL, "NULL", 32 }
};
GSList *
@@ -313,7 +177,7 @@ gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats)
return g_slist_reverse (targets);
}
-static Atom *
+Atom *
gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
gboolean include_special,
GdkContentFormats *formats,
@@ -332,8 +196,7 @@ gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
if (special_targets[i].mime_type != NULL)
continue;
- if (special_targets[i].handler)
- targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[i].x_target));
+ targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[i].x_target));
}
}
@@ -509,164 +372,6 @@ gdk_x11_clipboard_claim_remote (GdkX11Clipboard *cb,
gdk_x11_clipboard_request_targets (cb);
}
-static gboolean
-gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
- GdkX11PendingSelectionNotify *notify,
- Window requestor,
- const char *target,
- const char *property,
- gulong timestamp)
-{
- const char *mime_type;
- GdkDisplay *display;
- gsize i;
-
- display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
- mime_type = gdk_intern_mime_type (target);
-
- if (mime_type)
- {
- if (gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)), mime_type))
- {
- GOutputStream *stream;
-
- stream = gdk_x11_selection_output_stream_new (display,
- notify,
- requestor,
- cb->selection,
- target,
- property,
- target,
- 8,
- timestamp);
- gdk_x11_clipboard_default_output_handler (cb, target, stream);
- return TRUE;
- }
- }
- else if (g_str_equal (target, "MULTIPLE"))
- {
- gulong n_atoms;
- gulong nbytes;
- Atom prop_type;
- gint prop_format;
- Atom *atoms = NULL;
- int error;
-
- error = XGetWindowProperty (gdk_x11_display_get_xdisplay (display),
- requestor,
- gdk_x11_get_xatom_by_name_for_display (display, property),
- 0, 0x1FFFFFFF, False,
- AnyPropertyType,
- &prop_type, &prop_format,
- &n_atoms, &nbytes, (guchar **) &atoms);
- if (error != Success)
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("%s: XGetProperty() during MULTIPLE failed with %d\n",
- cb->selection, error));
- }
- else if (prop_format != 32 ||
- prop_type != gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("%s: XGetProperty() type/format should be ATOM_PAIR/32 but is
%s/%d\n",
- cb->selection, gdk_x11_get_xatom_name_for_display (display,
prop_type), prop_format));
- }
- else if (n_atoms < 2)
- {
- print_atoms (cb, "ignoring MULTIPLE request with too little elements", atoms, n_atoms);
- }
- else
- {
- gulong i;
-
- print_atoms (cb, "MULTIPLE request", atoms, n_atoms);
- if (n_atoms % 2)
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("%s: Number of atoms is uneven at %lu, ignoring last
element\n",
- cb->selection, n_atoms));
- n_atoms &= ~1;
- }
-
- gdk_x11_pending_selection_notify_require (notify, n_atoms / 2);
-
- for (i = 0; i < n_atoms / 2; i++)
- {
- gboolean success;
-
- if (atoms[2 * i] == None || atoms[2 * i + 1] == None)
- {
- success = FALSE;
- GDK_NOTE(CLIPBOARD, g_printerr ("%s: None not allowed as atom in MULTIPLE request\n",
- cb->selection));
- gdk_x11_pending_selection_notify_send (notify, display, FALSE);
- }
- else if (atoms[2 * i] == gdk_x11_get_xatom_by_name_for_display (display, "MULTIPLE"))
- {
- success = FALSE;
- GDK_NOTE(CLIPBOARD, g_printerr ("%s: MULTIPLE as target in MULTIPLE request would cause
recursion\n",
- cb->selection));
- gdk_x11_pending_selection_notify_send (notify, display, FALSE);
- }
- else
- {
- success = gdk_x11_clipboard_request_selection (cb,
- notify,
- requestor,
- gdk_x11_get_xatom_name_for_display
(display, atoms[2 * i]),
- gdk_x11_get_xatom_name_for_display
(display, atoms[2 * i + 1]),
- timestamp);
- }
-
- if (!success)
- atoms[2 * i + 1] = None;
- }
- }
-
- XChangeProperty (gdk_x11_display_get_xdisplay (display),
- requestor,
- gdk_x11_get_xatom_by_name_for_display (display, property),
- prop_type, 32,
- PropModeReplace, (guchar *)atoms, n_atoms);
-
- if (atoms)
- XFree (atoms);
-
- gdk_x11_pending_selection_notify_send (notify, display, TRUE);
- return TRUE;
- }
- else
- {
- for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
- {
- if (g_str_equal (target, special_targets[i].x_target) &&
- special_targets[i].handler)
- {
- GOutputStream *stream;
-
- if (special_targets[i].mime_type)
- mime_type = gdk_intern_mime_type (special_targets[i].mime_type);
- stream = gdk_x11_selection_output_stream_new (display,
- notify,
- requestor,
- cb->selection,
- target,
- property,
- special_targets[i].type,
- special_targets[i].format,
- timestamp);
- special_targets[i].handler (cb,
- target,
- special_targets[i].type,
- special_targets[i].format,
- stream);
- return TRUE;
- }
- }
- }
-
- gdk_x11_pending_selection_notify_send (notify, display, FALSE);
- return FALSE;
-}
-
static GdkFilterReturn
gdk_x11_clipboard_filter_event (GdkXEvent *xev,
GdkEvent *gdkevent,
@@ -732,7 +437,6 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
case SelectionRequest:
{
- GdkX11PendingSelectionNotify *notify;
const char *target, *property;
if (xevent->xselectionrequest.selection != cb->xselection)
@@ -760,19 +464,16 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
GDK_NOTE(CLIPBOARD, g_printerr ("%s: got SelectionRequest for %s @ %s\n",
cb->selection, target, property));
- notify = gdk_x11_pending_selection_notify_new (xevent->xselectionrequest.requestor,
- xevent->xselectionrequest.selection,
- xevent->xselectionrequest.target,
- xevent->xselectionrequest.property ?
xevent->xselectionrequest.property
- :
xevent->xselectionrequest.target,
- xevent->xselectionrequest.time);
-
- gdk_x11_clipboard_request_selection (cb,
- notify,
- xevent->xselectionrequest.requestor,
- target,
- property,
- xevent->xselectionrequest.time);
+ gdk_x11_selection_output_streams_create (display,
+ gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)),
+ xevent->xselectionrequest.requestor,
+ xevent->xselectionrequest.selection,
+ xevent->xselectionrequest.target,
+ xevent->xselectionrequest.property ?
xevent->xselectionrequest.property
+ :
xevent->xselectionrequest.target,
+ xevent->xselectionrequest.time,
+ gdk_x11_clipboard_default_output_handler,
+ cb);
return GDK_FILTER_REMOVE;
}
diff --git a/gdk/x11/gdkclipboard-x11.h b/gdk/x11/gdkclipboard-x11.h
index 0c0322d..e4b82ee 100644
--- a/gdk/x11/gdkclipboard-x11.h
+++ b/gdk/x11/gdkclipboard-x11.h
@@ -37,6 +37,10 @@ GdkClipboard * gdk_x11_clipboard_new (GdkDisplay
const gchar *selection);
GSList * gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats);
+Atom * gdk_x11_clipboard_formats_to_atoms (GdkDisplay *display,
+ gboolean include_special,
+ GdkContentFormats *formats,
+ gsize *n_atoms);
G_END_DECLS
diff --git a/gdk/x11/gdkselectionoutputstream-x11.c b/gdk/x11/gdkselectionoutputstream-x11.c
index 5a42421..2219004 100644
--- a/gdk/x11/gdkselectionoutputstream-x11.c
+++ b/gdk/x11/gdkselectionoutputstream-x11.c
@@ -23,12 +23,15 @@
#include "gdkselectionoutputstream-x11.h"
+#include "gdkclipboard-x11.h"
#include "gdkdisplay-x11.h"
#include "gdkintl.h"
+#include "gdktextlistconverter-x11.h"
#include "gdkx11display.h"
#include "gdkx11property.h"
#include "gdkx11window.h"
+typedef struct _GdkX11PendingSelectionNotify GdkX11PendingSelectionNotify;
typedef struct _GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
struct _GdkX11SelectionOutputStreamPrivate {
@@ -66,6 +69,84 @@ struct _GdkX11PendingSelectionNotify
G_DEFINE_TYPE_WITH_PRIVATE (GdkX11SelectionOutputStream, gdk_x11_selection_output_stream,
G_TYPE_OUTPUT_STREAM);
+static GdkX11PendingSelectionNotify *
+gdk_x11_pending_selection_notify_new (Window window,
+ Atom selection,
+ Atom target,
+ Atom property,
+ Time timestamp)
+{
+ GdkX11PendingSelectionNotify *pending;
+
+ pending = g_slice_new0 (GdkX11PendingSelectionNotify);
+ pending->n_pending = 1;
+
+ pending->xevent.type = SelectionNotify;
+ pending->xevent.serial = 0;
+ pending->xevent.send_event = True;
+ pending->xevent.requestor = window;
+ pending->xevent.selection = selection;
+ pending->xevent.target = target;
+ pending->xevent.property = property;
+ pending->xevent.time = timestamp;
+
+ return pending;
+}
+
+static void
+gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
+ guint n_sends)
+{
+ notify->n_pending += n_sends;
+}
+
+static void
+gdk_x11_pending_selection_notify_send (GdkX11PendingSelectionNotify *notify,
+ GdkDisplay *display,
+ gboolean success)
+{
+ Display *xdisplay;
+ int error;
+
+ notify->n_pending--;
+ if (notify->n_pending)
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: not sending SelectionNotify yet, %zu streams still pending\n",
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
+ notify->n_pending));
+ return;
+ }
+
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: sending SelectionNotify reporting %s\n",
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
+ success ? "success" : "failure"));
+ if (!success)
+ notify->xevent.property = None;
+
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+
+ gdk_x11_display_error_trap_push (display);
+
+ if (XSendEvent (xdisplay, notify->xevent.requestor, False, NoEventMask, (XEvent*) ¬ify->xevent) == 0)
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: failed to XSendEvent()\n",
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.target)));
+ }
+ XSync (xdisplay, False);
+
+ error = gdk_x11_display_error_trap_pop (display);
+ if (error != Success)
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: X error during write: %d\n",
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
+ gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
+ error));
+ }
+}
+
static GdkFilterReturn
gdk_x11_selection_output_stream_filter_event (GdkXEvent *xevent,
GdkEvent *gdkevent,
@@ -539,7 +620,7 @@ gdk_x11_selection_output_stream_filter_event (GdkXEvent *xev,
}
}
-GOutputStream *
+static GOutputStream *
gdk_x11_selection_output_stream_new (GdkDisplay *display,
GdkX11PendingSelectionNotify *notify,
Window window,
@@ -576,82 +657,386 @@ gdk_x11_selection_output_stream_new (GdkDisplay *display,
return G_OUTPUT_STREAM (stream);
}
-GdkX11PendingSelectionNotify *
-gdk_x11_pending_selection_notify_new (Window window,
- Atom selection,
- Atom target,
- Atom property,
- Time timestamp)
+static void
+print_atoms (GdkDisplay *display,
+ const char *selection,
+ const char *prefix,
+ const Atom *atoms,
+ gsize n_atoms)
{
- GdkX11PendingSelectionNotify *pending;
+ GDK_NOTE(CLIPBOARD,
+ gsize i;
+
+ g_printerr ("%s: %s [ ", selection, prefix);
+ for (i = 0; i < n_atoms; i++)
+ {
+ g_printerr ("%s%s", i > 0 ? ", " : "", gdk_x11_get_xatom_name_for_display (display ,
atoms[i]));
+ }
+ g_printerr (" ]\n");
+ );
+}
- pending = g_slice_new0 (GdkX11PendingSelectionNotify);
- pending->n_pending = 1;
+static void
+handle_targets_done (GObject *stream,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ gsize bytes_written;
- pending->xevent.type = SelectionNotify;
- pending->xevent.serial = 0;
- pending->xevent.send_event = True;
- pending->xevent.requestor = window;
- pending->xevent.selection = selection;
- pending->xevent.target = target;
- pending->xevent.property = property;
- pending->xevent.time = timestamp;
+ if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, &bytes_written, &error))
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("---: failed to send targets after %zu bytes: %s\n",
+ bytes_written, error->message));
+ g_error_free (error);
+ }
- return pending;
+ g_free (user_data);
}
-void
-gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
- guint n_sends)
+static void
+handle_targets (GOutputStream *stream,
+ GdkDisplay *display,
+ GdkContentFormats *formats,
+ const char *target,
+ const char *encoding,
+ int format,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
{
- notify->n_pending += n_sends;
+ Atom *atoms;
+ gsize n_atoms;
+
+ atoms = gdk_x11_clipboard_formats_to_atoms (display,
+ TRUE,
+ formats,
+ &n_atoms);
+ print_atoms (display, "---", "sending targets", atoms, n_atoms);
+ g_output_stream_write_all_async (stream,
+ atoms,
+ n_atoms * sizeof (Atom),
+ G_PRIORITY_DEFAULT,
+ NULL,
+ handle_targets_done,
+ atoms);
+ g_object_unref (stream);
}
-void
-gdk_x11_pending_selection_notify_send (GdkX11PendingSelectionNotify *notify,
- GdkDisplay *display,
- gboolean success)
+static void
+handle_timestamp_done (GObject *stream,
+ GAsyncResult *result,
+ gpointer user_data)
{
- Display *xdisplay;
- int error;
+ GError *error = NULL;
+ gsize bytes_written;
- notify->n_pending--;
- if (notify->n_pending)
+ if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, &bytes_written, &error))
{
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: not sending SelectionNotify yet, %zu streams still pending\n",
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
- notify->n_pending));
- return;
+ GDK_NOTE(CLIPBOARD, g_printerr ("---: failed to send timestamp after %zu bytes: %s\n",
+ bytes_written, error->message));
+ g_error_free (error);
}
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: sending SelectionNotify reporting %s\n",
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
- success ? "success" : "failure"));
- if (!success)
- notify->xevent.property = None;
+ g_slice_free (gulong, user_data);
+}
- xdisplay = gdk_x11_display_get_xdisplay (display);
+static void
+handle_timestamp (GOutputStream *stream,
+ GdkDisplay *display,
+ GdkContentFormats *formats,
+ const char *target,
+ const char *encoding,
+ int format,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ gulong *time_;
+
+ time_ = g_slice_new (gulong);
+ *time_ = timestamp;
+
+ g_output_stream_write_all_async (stream,
+ time_,
+ sizeof (gulong),
+ G_PRIORITY_DEFAULT,
+ NULL,
+ handle_timestamp_done,
+ time_);
+ g_object_unref (stream);
+}
- gdk_x11_display_error_trap_push (display);
+static void
+handle_save_targets (GOutputStream *stream,
+ GdkDisplay *display,
+ GdkContentFormats *formats,
+ const char *target,
+ const char *encoding,
+ int format,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ /* Don't do anything */
- if (XSendEvent (xdisplay, notify->xevent.requestor, False, NoEventMask, (XEvent*) ¬ify->xevent) == 0)
+ g_object_unref (stream);
+}
+
+static void
+handle_text_list (GOutputStream *stream,
+ GdkDisplay *display,
+ GdkContentFormats *formats,
+ const char *target,
+ const char *encoding,
+ int format,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ GOutputStream *converter_stream;
+ GConverter *converter;
+
+ converter = gdk_x11_text_list_converter_to_utf8_new (display,
+ encoding,
+ format);
+ converter_stream = g_converter_output_stream_new (stream, converter);
+
+ g_object_unref (converter);
+ g_object_unref (stream);
+
+ handler (converter_stream, gdk_intern_mime_type ("text/plain;charset=utf-8"), user_data);
+}
+
+static void
+handle_utf8 (GOutputStream *stream,
+ GdkDisplay *display,
+ GdkContentFormats *formats,
+ const char *target,
+ const char *encoding,
+ int format,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ handler (stream, gdk_intern_mime_type ("text/plain;charset=utf-8"), user_data);
+}
+
+typedef void (* MimeTypeHandleFunc) (GOutputStream *, GdkDisplay *, GdkContentFormats *, const char *, const
char *, int, gulong, GdkX11SelectionOutputHandler, gpointer);
+
+static const struct {
+ const char *x_target;
+ const char *mime_type;
+ const char *type;
+ gint format;
+ MimeTypeHandleFunc handler;
+} special_targets[] = {
+ { "UTF8_STRING", "text/plain;charset=utf-8", "UTF8_STRING", 8, handle_utf8 },
+ { "COMPOUND_TEXT", "text/plain;charset=utf-8", "COMPOUND_TEXT", 8, handle_text_list },
+ { "TEXT", "text/plain;charset=utf-8", "STRING", 8, handle_text_list },
+ { "STRING", "text/plain;charset=utf-8", "STRING", 8, handle_text_list },
+ { "TARGETS", NULL, "ATOM", 32, handle_targets },
+ { "TIMESTAMP", NULL, "INTEGER", 32, handle_timestamp },
+ { "SAVE_TARGETS", NULL, "NULL", 32, handle_save_targets }
+};
+
+static gboolean
+gdk_x11_selection_output_streams_request (GdkDisplay *display,
+ GdkX11PendingSelectionNotify *notify,
+ GdkContentFormats *formats,
+ Window requestor,
+ Atom xselection,
+ Atom xtarget,
+ Atom xproperty,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ const char *mime_type, *selection, *target, *property;
+ gsize i;
+
+ selection = gdk_x11_get_xatom_name_for_display (display, xselection);
+ target = gdk_x11_get_xatom_name_for_display (display, xtarget);
+ property = gdk_x11_get_xatom_name_for_display (display, xproperty);
+ mime_type = gdk_intern_mime_type (target);
+
+ if (mime_type)
{
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: failed to XSendEvent()\n",
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.target)));
+ if (gdk_content_formats_contain_mime_type (formats, mime_type))
+ {
+ GOutputStream *stream;
+
+ stream = gdk_x11_selection_output_stream_new (display,
+ notify,
+ requestor,
+ selection,
+ target,
+ property,
+ target,
+ 8,
+ timestamp);
+ handler (stream, target, user_data);
+ return TRUE;
+ }
}
- XSync (xdisplay, False);
+ else if (g_str_equal (target, "MULTIPLE"))
+ {
+ gulong n_atoms;
+ gulong nbytes;
+ Atom prop_type;
+ gint prop_format;
+ Atom *atoms = NULL;
+ int error;
+
+ error = XGetWindowProperty (gdk_x11_display_get_xdisplay (display),
+ requestor,
+ xproperty,
+ 0, 0x1FFFFFFF, False,
+ AnyPropertyType,
+ &prop_type, &prop_format,
+ &n_atoms, &nbytes, (guchar **) &atoms);
+ if (error != Success)
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s: XGetProperty() during MULTIPLE failed with %d\n",
+ selection, error));
+ }
+ else if (prop_format != 32 ||
+ prop_type != gdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s: XGetProperty() type/format should be ATOM_PAIR/32 but is
%s/%d\n",
+ selection, gdk_x11_get_xatom_name_for_display (display,
prop_type), prop_format));
+ }
+ else if (n_atoms < 2)
+ {
+ print_atoms (display, selection, "ignoring MULTIPLE request with too little elements", atoms,
n_atoms);
+ }
+ else
+ {
+ gulong i;
+
+ print_atoms (display, selection, "MULTIPLE request", atoms, n_atoms);
+ if (n_atoms % 2)
+ {
+ GDK_NOTE(SELECTION, g_printerr ("%s: Number of atoms is uneven at %lu, ignoring last
element\n",
+ selection, n_atoms));
+ n_atoms &= ~1;
+ }
+
+ gdk_x11_pending_selection_notify_require (notify, n_atoms / 2);
+
+ for (i = 0; i < n_atoms / 2; i++)
+ {
+ gboolean success;
+
+ if (atoms[2 * i] == None || atoms[2 * i + 1] == None)
+ {
+ success = FALSE;
+ GDK_NOTE(SELECTION, g_printerr ("%s: None not allowed as atom in MULTIPLE request\n",
+ selection));
+ gdk_x11_pending_selection_notify_send (notify, display, FALSE);
+ }
+ else if (atoms[2 * i] == gdk_x11_get_xatom_by_name_for_display (display, "MULTIPLE"))
+ {
+ success = FALSE;
+ GDK_NOTE(SELECTION, g_printerr ("%s: MULTIPLE as target in MULTIPLE request would cause
recursion\n",
+ selection));
+ gdk_x11_pending_selection_notify_send (notify, display, FALSE);
+ }
+ else
+ {
+ success = gdk_x11_selection_output_streams_request (display,
+ notify,
+ formats,
+ requestor,
+ xselection,
+ atoms[2 * i],
+ atoms[2 * i + 1],
+ timestamp,
+ handler,
+ user_data);
+ }
+
+ if (!success)
+ atoms[2 * i + 1] = None;
+ }
+ }
- error = gdk_x11_display_error_trap_pop (display);
- if (error != Success)
+ XChangeProperty (gdk_x11_display_get_xdisplay (display),
+ requestor,
+ xproperty,
+ prop_type, 32,
+ PropModeReplace, (guchar *)atoms, n_atoms);
+
+ if (atoms)
+ XFree (atoms);
+
+ gdk_x11_pending_selection_notify_send (notify, display, TRUE);
+ return TRUE;
+ }
+ else
{
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: X error during write: %d\n",
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.selection),
- gdk_x11_get_xatom_name_for_display (display, notify->xevent.target),
- error));
+ for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
+ {
+ if (g_str_equal (target, special_targets[i].x_target) &&
+ special_targets[i].handler)
+ {
+ GOutputStream *stream;
+
+ if (special_targets[i].mime_type)
+ mime_type = gdk_intern_mime_type (special_targets[i].mime_type);
+ stream = gdk_x11_selection_output_stream_new (display,
+ notify,
+ requestor,
+ selection,
+ target,
+ property,
+ special_targets[i].type,
+ special_targets[i].format,
+ timestamp);
+ special_targets[i].handler (stream,
+ display,
+ formats,
+ target,
+ special_targets[i].type,
+ special_targets[i].format,
+ timestamp,
+ handler,
+ user_data);
+ return TRUE;
+ }
+ }
}
+
+ gdk_x11_pending_selection_notify_send (notify, display, FALSE);
+ return FALSE;
}
+void
+gdk_x11_selection_output_streams_create (GdkDisplay *display,
+ GdkContentFormats *formats,
+ Window requestor,
+ Atom selection,
+ Atom target,
+ Atom property,
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data)
+{
+ GdkX11PendingSelectionNotify *notify;
+ notify = gdk_x11_pending_selection_notify_new (requestor,
+ selection,
+ target,
+ property,
+ timestamp);
+ gdk_x11_selection_output_streams_request (display,
+ notify,
+ formats,
+ requestor,
+ selection,
+ target,
+ property,
+ timestamp,
+ handler,
+ user_data);
+}
diff --git a/gdk/x11/gdkselectionoutputstream-x11.h b/gdk/x11/gdkselectionoutputstream-x11.h
index 7b4c09c..03a0d30 100644
--- a/gdk/x11/gdkselectionoutputstream-x11.h
+++ b/gdk/x11/gdkselectionoutputstream-x11.h
@@ -36,11 +36,11 @@ G_BEGIN_DECLS
#define GDK_IS_X11_SELECTION_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GDK_TYPE_X11_SELECTION_OUTPUT_STREAM))
#define GDK_X11_SELECTION_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GDK_TYPE_X11_SELECTION_OUTPUT_STREAM, GdkX11SelectionOutputStreamClass))
-typedef struct _GdkX11PendingSelectionNotify GdkX11PendingSelectionNotify;
-
typedef struct GdkX11SelectionOutputStream GdkX11SelectionOutputStream;
typedef struct GdkX11SelectionOutputStreamClass GdkX11SelectionOutputStreamClass;
+typedef void (* GdkX11SelectionOutputHandler) (GOutputStream *stream, const char *mime_type, gpointer
user_data);
+
struct GdkX11SelectionOutputStream
{
GOutputStream parent_instance;
@@ -54,27 +54,15 @@ struct GdkX11SelectionOutputStreamClass
GType gdk_x11_selection_output_stream_get_type (void) G_GNUC_CONST;
-GOutputStream * gdk_x11_selection_output_stream_new (GdkDisplay *display,
- GdkX11PendingSelectionNotify *notify,
- Window window,
- const char *selection,
- const char *target,
- const char *property,
- const char *type,
- int format,
- gulong timestamp);
-
-GdkX11PendingSelectionNotify *
- gdk_x11_pending_selection_notify_new (Window window,
+void gdk_x11_selection_output_streams_create (GdkDisplay *display,
+ GdkContentFormats *formats,
+ Window requestor,
Atom selection,
Atom target,
Atom property,
- Time timestamp);
-void gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
- guint n_sends);
-void gdk_x11_pending_selection_notify_send (GdkX11PendingSelectionNotify *notify,
- GdkDisplay *display,
- gboolean success);
+ gulong timestamp,
+ GdkX11SelectionOutputHandler handler,
+ gpointer user_data);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]