[gtk+/wip/otte/clipboard: 2/11] x11: Add an initial clipboard implementation
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/clipboard: 2/11] x11: Add an initial clipboard implementation
- Date: Wed, 22 Nov 2017 11:24:19 +0000 (UTC)
commit 4be60b28280ed1f89f8d0ebd8da785651df3b618
Author: Benjamin Otte <otte redhat com>
Date: Sun Nov 19 18:06:13 2017 +0100
x11: Add an initial clipboard implementation
This does nothing but download the targets and debug-print them.
gdk/gdk.c | 4 +-
gdk/gdkinternals.h | 4 +-
gdk/x11/gdkclipboard-x11.c | 192 ++++++++++++++
gdk/x11/gdkclipboard-x11.h | 46 ++++
gdk/x11/gdkdisplay-x11.c | 40 ++-
gdk/x11/gdkdisplay-x11.h | 3 +
gdk/x11/gdkselectioninputstream-x11.c | 443 +++++++++++++++++++++++++++++++++
gdk/x11/gdkselectioninputstream-x11.h | 59 +++++
gdk/x11/meson.build | 2 +
9 files changed, 779 insertions(+), 14 deletions(-)
---
diff --git a/gdk/gdk.c b/gdk/gdk.c
index d04bf41..28eb0fe 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -166,7 +166,9 @@ static const GDebugKey gdk_debug_keys[] = {
{ "frames", GDK_DEBUG_FRAMES },
{ "settings", GDK_DEBUG_SETTINGS },
{ "opengl", GDK_DEBUG_OPENGL },
- { "vulkan", GDK_DEBUG_VULKAN }
+ { "vulkan", GDK_DEBUG_VULKAN },
+ { "selection", GDK_DEBUG_SELECTION },
+ { "clipboard", GDK_DEBUG_CLIPBOARD }
};
#endif
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 0ef2aaa..0411997 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -70,7 +70,9 @@ typedef enum {
GDK_DEBUG_FRAMES = 1 << 10,
GDK_DEBUG_SETTINGS = 1 << 11,
GDK_DEBUG_OPENGL = 1 << 12,
- GDK_DEBUG_VULKAN = 1 << 13
+ GDK_DEBUG_VULKAN = 1 << 13,
+ GDK_DEBUG_SELECTION = 1 << 14,
+ GDK_DEBUG_CLIPBOARD = 1 << 15
} GdkDebugFlag;
typedef enum {
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
new file mode 100644
index 0000000..4a90d8a
--- /dev/null
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -0,0 +1,192 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkclipboardprivate.h"
+#include "gdkclipboard-x11.h"
+#include "gdkselectioninputstream-x11.h"
+#include "gdkprivate-x11.h"
+
+#include <string.h>
+#include <X11/Xatom.h>
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#define IDLE_ABORT_TIME 30 /* seconds */
+
+typedef struct _GdkX11ClipboardClass GdkX11ClipboardClass;
+
+typedef struct _RetrievalInfo RetrievalInfo;
+
+struct _GdkX11Clipboard
+{
+ GdkClipboard parent;
+
+ char *selection;
+ Atom xselection;
+ guint32 time;
+};
+
+struct _GdkX11ClipboardClass
+{
+ GdkClipboardClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkX11Clipboard, gdk_x11_clipboard, GDK_TYPE_CLIPBOARD)
+
+static void
+gdk_x11_clipboard_finalize (GObject *object)
+{
+ GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (object);
+
+ g_free (cb->selection);
+
+ G_OBJECT_CLASS (gdk_x11_clipboard_parent_class)->finalize (object);
+}
+
+static void
+gdk_x11_clipboard_class_init (GdkX11ClipboardClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ //GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (class);
+
+ object_class->finalize = gdk_x11_clipboard_finalize;
+}
+
+static void
+gdk_x11_clipboard_init (GdkX11Clipboard *clipboard)
+{
+}
+
+#define SELECTION_MAX_SIZE(display) \
+ MIN(262144, \
+ XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
+ ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
+ : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
+
+static void
+gdk_x11_clipboard_request_targets_finish (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GInputStream *stream = G_INPUT_STREAM (source_object);
+ GdkX11Clipboard *cb = user_data;
+ GdkDisplay *display;
+ GdkContentFormats *formats;
+ GdkContentFormatsBuilder *builder;
+ GBytes *bytes;
+ GError *error = NULL;
+ const Atom *atoms;
+ guint i, n_atoms;
+
+ bytes = g_input_stream_read_bytes_finish (stream, res, &error);
+ if (bytes == NULL || g_bytes_get_size (bytes) == 0)
+ {
+ if (bytes)
+ g_bytes_unref (bytes);
+ g_object_unref (stream);
+ g_object_unref (cb);
+ return;
+ }
+
+ display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+
+ atoms = g_bytes_get_data (bytes, NULL);
+ n_atoms = g_bytes_get_size (bytes) / sizeof (Atom);
+ builder = gdk_content_formats_builder_new ();
+ for (i = 0; i < n_atoms; i++)
+ {
+ gdk_content_formats_builder_add_mime_type (builder, gdk_x11_get_xatom_name_for_display (display ,
atoms[i]));
+ }
+ formats = gdk_content_formats_builder_free (builder);
+ GDK_NOTE(CLIPBOARD, char *s = gdk_content_formats_to_string (formats); g_printerr ("%s: got formats:
%s\n", cb->selection, s); g_free (s));
+
+ g_input_stream_read_bytes_async (stream,
+ SELECTION_MAX_SIZE (display),
+ G_PRIORITY_DEFAULT,
+ NULL,
+ gdk_x11_clipboard_request_targets_finish,
+ cb);
+}
+
+static void
+gdk_x11_clipboard_request_targets (GdkX11Clipboard *cb)
+{
+ GInputStream *stream;
+ GdkDisplay *display;
+
+ display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+
+ stream = gdk_x11_selection_input_stream_new (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
+ cb->selection,
+ "TARGETS");
+
+ g_input_stream_read_bytes_async (stream,
+ SELECTION_MAX_SIZE (display),
+ G_PRIORITY_DEFAULT,
+ NULL,
+ gdk_x11_clipboard_request_targets_finish,
+ g_object_ref (cb));
+}
+
+GdkClipboard *
+gdk_x11_clipboard_new (GdkDisplay *display,
+ const gchar *selection)
+{
+ GdkX11Clipboard *cb;
+
+ cb = g_object_new (GDK_TYPE_X11_CLIPBOARD,
+ "display", display,
+ NULL);
+
+ cb->selection = g_strdup (selection);
+ cb->xselection = gdk_x11_get_xatom_by_name_for_display (display, selection);
+
+ gdk_display_request_selection_notification (display, gdk_atom_intern (selection, FALSE));
+ gdk_x11_clipboard_request_targets (cb);
+
+ return GDK_CLIPBOARD (cb);
+}
+
+gboolean
+gdk_x11_clipboard_handle_event (GdkX11Clipboard *cb,
+ XEvent *xevent)
+{
+ return FALSE;
+}
+
+gboolean
+gdk_x11_clipboard_handle_selection_notify (GdkX11Clipboard *cb,
+ XEvent *xevent)
+{
+#ifdef HAVE_XFIXES
+ GdkDisplay *display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+ XFixesSelectionNotifyEvent *event = (XFixesSelectionNotifyEvent *)xevent;
+
+ if (event->window != GDK_X11_DISPLAY (display)->leader_window ||
+ event->selection != cb->xselection)
+ return FALSE;
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
diff --git a/gdk/x11/gdkclipboard-x11.h b/gdk/x11/gdkclipboard-x11.h
new file mode 100644
index 0000000..fa8485d
--- /dev/null
+++ b/gdk/x11/gdkclipboard-x11.h
@@ -0,0 +1,46 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_CLIPBOARD_X11_H__
+#define __GDK_CLIPBOARD_X11_H__
+
+#include "gdk/gdkclipboard.h"
+
+#include <X11/Xlib.h>
+
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_X11_CLIPBOARD (gdk_x11_clipboard_get_type ())
+#define GDK_X11_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_X11_CLIPBOARD,
GdkX11Clipboard))
+#define GDK_IS_X11_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_X11_CLIPBOARD))
+
+typedef struct _GdkX11Clipboard GdkX11Clipboard;
+
+GType gdk_x11_clipboard_get_type (void) G_GNUC_CONST;
+
+GdkClipboard * gdk_x11_clipboard_new (GdkDisplay *display,
+ const gchar *selection);
+
+gboolean gdk_x11_clipboard_handle_event (GdkX11Clipboard *clipboard,
+ XEvent *xevent);
+gboolean gdk_x11_clipboard_handle_selection_notify(GdkX11Clipboard *clipboard,
+ XEvent *xevent);
+
+G_END_DECLS
+
+#endif /* __GDK_CLIPBOARD_X11_H__ */
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 245df4a..5faa0de 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -24,6 +24,9 @@
#define VK_USE_PLATFORM_XLIB_KHR
+#include "gdkdisplay-x11.h"
+#include "gdkdisplayprivate.h"
+
#include "gdkasync.h"
#include "gdkdisplay.h"
#include "gdkeventsource.h"
@@ -35,13 +38,12 @@
#include "gdkkeysprivate.h"
#include "gdkdevicemanager.h"
#include "xsettings-client.h"
-#include "gdkdisplay-x11.h"
+#include "gdkclipboard-x11.h"
#include "gdkprivate-x11.h"
#include "gdkscreen-x11.h"
#include "gdkglcontext-x11.h"
#include "gdkvulkancontext-x11.h"
#include "gdk-private.h"
-#include "gdkdisplayprivate.h"
#include <glib.h>
#include <glib/gprintf.h>
@@ -1141,16 +1143,24 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
gdk_display_set_composited (display, composited);
}
- event->owner_change.type = GDK_OWNER_CHANGE;
- event->owner_change.window = window;
- event->owner_change.reason = selection_notify->subtype;
- event->owner_change.selection =
- gdk_x11_xatom_to_atom_for_display (display,
- selection_notify->selection);
- event->owner_change.time = selection_notify->timestamp;
- event->owner_change.selection_time = selection_notify->selection_timestamp;
-
- return_val = TRUE;
+ if (gdk_x11_clipboard_handle_selection_notify (GDK_X11_CLIPBOARD (display->clipboard), xevent) ||
+ gdk_x11_clipboard_handle_selection_notify (GDK_X11_CLIPBOARD (display->primary_clipboard),
xevent))
+ {
+ return_val = FALSE;
+ }
+ else
+ {
+ event->owner_change.type = GDK_OWNER_CHANGE;
+ event->owner_change.window = window;
+ event->owner_change.reason = selection_notify->subtype;
+ event->owner_change.selection =
+ gdk_x11_xatom_to_atom_for_display (display,
+ selection_notify->selection);
+ event->owner_change.time = selection_notify->timestamp;
+ event->owner_change.selection_time = selection_notify->selection_timestamp;
+
+ return_val = TRUE;
+ }
}
else
#endif
@@ -1741,6 +1751,9 @@ gdk_x11_display_open (const gchar *display_name)
}
#endif
+ display->clipboard = gdk_x11_clipboard_new (display, "CLIPBOARD");
+ display->primary_clipboard = gdk_x11_clipboard_new (display, "PRIMARY");
+
/*
* It is important that we first request the selection
* notification, and then setup the initial state of
@@ -2053,6 +2066,9 @@ gdk_x11_display_finalize (GObject *object)
/* Empty the event queue */
_gdk_x11_display_free_translate_queue (GDK_DISPLAY (display_x11));
+ /* Get rid of pending streams */
+ g_slist_free_full (display_x11->input_streams, g_object_unref);
+
/* Atom Hashtable */
g_hash_table_destroy (display_x11->atom_from_virtual);
g_hash_table_destroy (display_x11->atom_to_virtual);
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index adee9f2..4c7a2e2 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -104,6 +104,9 @@ struct _GdkX11Display
/* translation queue */
GQueue *translate_queue;
+ /* streams reading selections */
+ GSList *input_streams;
+
/* input GdkWindow list */
GList *input_windows;
diff --git a/gdk/x11/gdkselectioninputstream-x11.c b/gdk/x11/gdkselectioninputstream-x11.c
new file mode 100644
index 0000000..9a4965c
--- /dev/null
+++ b/gdk/x11/gdkselectioninputstream-x11.c
@@ -0,0 +1,443 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ * Christian Kellner <gicmo gnome org>
+ */
+
+#include "config.h"
+
+#include "gdkselectioninputstream-x11.h"
+
+#include "gdkdisplay-x11.h"
+#include "gdkintl.h"
+#include "gdkx11display.h"
+#include "gdkx11property.h"
+#include "gdkx11window.h"
+
+typedef struct GdkX11SelectionInputStreamPrivate GdkX11SelectionInputStreamPrivate;
+
+struct GdkX11SelectionInputStreamPrivate {
+ GdkDisplay *display;
+ GQueue chunks;
+ char *selection;
+ Atom xselection;
+ char *target;
+ Atom xtarget;
+ char *property;
+ Atom xproperty;
+
+ GTask *pending_task;
+ guchar *pending_data;
+ gsize pending_size;
+
+ guint complete : 1;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GdkX11SelectionInputStream, gdk_x11_selection_input_stream, G_TYPE_INPUT_STREAM);
+
+static GdkFilterReturn
+gdk_x11_selection_input_stream_filter_event (GdkXEvent *xevent,
+ GdkEvent *gdkevent,
+ gpointer data);
+
+static gboolean
+gdk_x11_selection_input_stream_has_data (GdkX11SelectionInputStream *stream)
+{
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+
+ return !g_queue_is_empty (&priv->chunks) || priv->complete;
+}
+
+static gssize
+gdk_x11_selection_input_stream_fill_buffer (GdkX11SelectionInputStream *stream,
+ guchar *buffer,
+ gsize count)
+{
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+ gssize result = 0;
+
+ while (!g_queue_is_empty (&priv->chunks) && count > 0)
+ {
+ GBytes *bytes = g_queue_pop_head (&priv->chunks);
+ gsize size = g_bytes_get_size (bytes);
+
+ if (g_bytes_get_size (bytes) > count)
+ {
+ GBytes *subbytes;
+ if (buffer)
+ memcpy (buffer, g_bytes_get_data (bytes, NULL), count);
+ subbytes = g_bytes_new_from_bytes (bytes, count, size - count);
+ g_queue_push_head (&priv->chunks, subbytes);
+ size = count;
+ }
+ else
+ {
+ if (buffer)
+ memcpy (buffer, g_bytes_get_data (bytes, NULL), size);
+ }
+
+ g_bytes_unref (bytes);
+ result += size;
+ if (buffer)
+ buffer += size;
+ count -= size;
+ }
+
+ return result;
+}
+
+static void
+gdk_x11_selection_input_stream_flush (GdkX11SelectionInputStream *stream)
+{
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+ gssize written;
+
+ if (!gdk_x11_selection_input_stream_has_data (stream))
+ return;
+
+ if (priv->pending_task == NULL)
+ return;
+
+ written = gdk_x11_selection_input_stream_fill_buffer (stream, priv->pending_data, priv->pending_size);
+ g_task_return_int (priv->pending_task, written);
+
+ priv->pending_task = NULL;
+ priv->pending_data = NULL;
+ priv->pending_size = 0;
+}
+
+static void
+gdk_x11_selection_input_stream_complete (GdkX11SelectionInputStream *stream)
+{
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+
+ if (priv->complete)
+ return;
+
+ priv->complete = TRUE;
+
+ gdk_x11_selection_input_stream_flush (stream);
+
+ GDK_X11_DISPLAY (priv->display)->input_streams = g_slist_remove (GDK_X11_DISPLAY
(priv->display)->input_streams, stream);
+ gdk_window_remove_filter (GDK_X11_DISPLAY (priv->display)->leader_gdk_window,
gdk_x11_selection_input_stream_filter_event, stream);
+
+ g_object_unref (stream);
+}
+
+static gssize
+gdk_x11_selection_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("X11 Selections cannot be read synchronously"));
+
+ return -1;
+}
+
+static gboolean
+gdk_x11_selection_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return TRUE;
+}
+
+static void
+gdk_x11_selection_input_stream_read_async (GInputStream *input_stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkX11SelectionInputStream *stream = GDK_X11_SELECTION_INPUT_STREAM (input_stream);
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+ GTask *task;
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gdk_x11_selection_input_stream_read_async);
+ g_task_set_priority (task, io_priority);
+
+ if (gdk_x11_selection_input_stream_has_data (stream))
+ {
+ gssize size;
+
+ size = gdk_x11_selection_input_stream_fill_buffer (stream, buffer, count);
+ g_task_return_int (task, size);
+ }
+ else
+ {
+ priv->pending_data = buffer;
+ priv->pending_size = count;
+ priv->pending_task = task;
+ }
+}
+
+static gssize
+gdk_x11_selection_input_stream_read_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, stream), -1);
+
+ return g_task_propagate_int (G_TASK (result), error);
+}
+
+static void
+gdk_x11_selection_input_stream_close_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gdk_x11_selection_input_stream_close_async);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static gboolean
+gdk_x11_selection_input_stream_close_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ return TRUE;
+}
+
+static void
+gdk_x11_selection_input_stream_finalize (GObject *object)
+{
+ GdkX11SelectionInputStream *stream = GDK_X11_SELECTION_INPUT_STREAM (object);
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+
+ gdk_x11_selection_input_stream_complete (stream);
+
+ g_queue_foreach (&priv->chunks, (GFunc) g_bytes_unref, NULL);
+ g_queue_clear (&priv->chunks);
+
+ g_free (priv->selection);
+ g_free (priv->target);
+ g_free (priv->property);
+
+ G_OBJECT_CLASS (gdk_x11_selection_input_stream_parent_class)->finalize (object);
+}
+
+static void
+gdk_x11_selection_input_stream_class_init (GdkX11SelectionInputStreamClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS (klass);
+
+ object_class->finalize = gdk_x11_selection_input_stream_finalize;
+
+ istream_class->read_fn = gdk_x11_selection_input_stream_read;
+ istream_class->close_fn = gdk_x11_selection_input_stream_close;
+
+ istream_class->read_async = gdk_x11_selection_input_stream_read_async;
+ istream_class->read_finish = gdk_x11_selection_input_stream_read_finish;
+ istream_class->close_async = gdk_x11_selection_input_stream_close_async;
+ istream_class->close_finish = gdk_x11_selection_input_stream_close_finish;
+}
+
+static void
+gdk_x11_selection_input_stream_init (GdkX11SelectionInputStream *stream)
+{
+}
+
+static void
+XFree_without_return_value (gpointer data)
+{
+ XFree (data);
+}
+
+static GBytes *
+get_selection_property (Display *display,
+ Window owner,
+ Atom property,
+ Atom *ret_type,
+ gint *ret_format)
+{
+ gulong nitems;
+ gulong nbytes;
+ Atom prop_type;
+ gint prop_format;
+ guchar *data = NULL;
+
+ if (XGetWindowProperty (display, owner, property,
+ 0, 0x1FFFFFFF, False,
+ AnyPropertyType, &prop_type, &prop_format,
+ &nitems, &nbytes, &data) != Success)
+ goto err;
+
+ if (prop_type != None)
+ {
+ gsize length;
+
+ switch (prop_format)
+ {
+ case 8:
+ length = nitems;
+ break;
+ case 16:
+ length = sizeof (short) * nitems;
+ break;
+ case 32:
+ length = sizeof (long) * nitems;
+ break;
+ default:
+ g_warning ("Unknown XGetWindowProperty() format %u", prop_format);
+ goto err;
+ }
+
+ *ret_type = prop_type;
+ *ret_format = prop_format;
+
+ return g_bytes_new_with_free_func (data,
+ length,
+ XFree_without_return_value,
+ data);
+ }
+
+err:
+ if (data)
+ XFree (data);
+
+ *ret_type = None;
+ *ret_format = 0;
+
+ return NULL;
+}
+
+
+static GdkFilterReturn
+gdk_x11_selection_input_stream_filter_event (GdkXEvent *xev,
+ GdkEvent *gdkevent,
+ gpointer data)
+{
+ GdkX11SelectionInputStream *stream = GDK_X11_SELECTION_INPUT_STREAM (data);
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+ XEvent *xevent = xev;
+ Display *xdisplay;
+ Window xwindow;
+
+#if 0
+ GList *tmp_list;
+ GtkRetrievalInfo *info = NULL;
+ GdkWindow *window;
+ GBytes *bytes;
+ gint length;
+ GdkAtom type;
+ GdkAtom selection;
+ GdkAtom property;
+ gint format;
+ guint32 time;
+#endif
+
+ xdisplay = gdk_x11_display_get_xdisplay (priv->display);
+ xwindow = GDK_X11_DISPLAY (priv->display)->leader_window;
+
+ if (xevent->xany.window != xwindow)
+ return GDK_FILTER_CONTINUE;
+
+ switch (xevent->type)
+ {
+ case SelectionNotify:
+ {
+ GBytes *bytes;
+ Atom type;
+ gint format;
+
+ if (priv->xselection != xevent->xselection.selection ||
+ priv->xtarget != xevent->xselection.target)
+ return GDK_FILTER_CONTINUE;
+
+ GDK_NOTE(SELECTION, g_print ("%s:%s: got SelectionNotify\n", priv->selection, priv->target));
+
+ if (xevent->xselection.property != None)
+ bytes = get_selection_property (xdisplay, xwindow, xevent->xselection.property, &type, &format);
+ else
+ bytes = NULL;
+
+ if (bytes == NULL)
+ {
+ gdk_x11_selection_input_stream_complete (stream);
+ }
+ else
+ {
+ g_queue_push_tail (&priv->chunks, bytes);
+
+ if (type == gdk_x11_get_xatom_by_name_for_display (priv->display, "INCR"))
+ {
+ /* The remainder of the selection will come through PropertyNotify
+ events on xwindow */
+ GDK_NOTE(SELECTION, g_print ("%s:%s: initiating INCR transfer\n", priv->selection,
priv->target));
+ gdk_x11_selection_input_stream_flush (stream);
+ }
+ else
+ {
+ gdk_x11_selection_input_stream_complete (stream);
+ }
+
+ XDeleteProperty (xdisplay, xwindow, xevent->xselection.property);
+ }
+ }
+ return GDK_FILTER_REMOVE;
+
+ default:
+ return GDK_FILTER_CONTINUE;
+ }
+}
+
+GInputStream *
+gdk_x11_selection_input_stream_new (GdkDisplay *display,
+ const char *selection,
+ const char *target)
+{
+ GdkX11SelectionInputStream *stream;
+ GdkX11SelectionInputStreamPrivate *priv;
+
+ stream = g_object_new (GDK_TYPE_X11_SELECTION_INPUT_STREAM, NULL);
+ priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+
+ priv->display = display;
+ GDK_X11_DISPLAY (display)->input_streams = g_slist_prepend (GDK_X11_DISPLAY (display)->input_streams,
stream);
+ priv->selection = g_strdup (selection);
+ priv->xselection = gdk_x11_get_xatom_by_name_for_display (display, priv->selection);
+ priv->target = g_strdup (target);
+ priv->xtarget = gdk_x11_get_xatom_by_name_for_display (display, priv->target);
+ priv->property = g_strdup_printf ("GDK_SELECTION_%p", stream);
+ priv->xproperty = gdk_x11_get_xatom_by_name_for_display (display, priv->property);
+
+ gdk_window_add_filter (NULL, gdk_x11_selection_input_stream_filter_event, stream);
+
+ XConvertSelection (GDK_DISPLAY_XDISPLAY (display),
+ priv->xselection,
+ priv->xtarget,
+ priv->xproperty,
+ GDK_X11_DISPLAY (display)->leader_window,
+ CurrentTime);
+
+ return g_object_ref (stream);
+}
+
diff --git a/gdk/x11/gdkselectioninputstream-x11.h b/gdk/x11/gdkselectioninputstream-x11.h
new file mode 100644
index 0000000..9947329
--- /dev/null
+++ b/gdk/x11/gdkselectioninputstream-x11.h
@@ -0,0 +1,59 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ * Christian Kellner <gicmo gnome org>
+ */
+
+#ifndef __GDK_X11_SELECTION_INPUT_STREAM_H__
+#define __GDK_X11_SELECTION_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#include "gdktypes.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_X11_SELECTION_INPUT_STREAM (gdk_x11_selection_input_stream_get_type ())
+#define GDK_X11_SELECTION_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GDK_TYPE_X11_SELECTION_INPUT_STREAM, GdkX11SelectionInputStream))
+#define GDK_X11_SELECTION_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k),
GDK_TYPE_X11_SELECTION_INPUT_STREAM, GdkX11SelectionInputStreamClass))
+#define GDK_IS_X11_SELECTION_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GDK_TYPE_X11_SELECTION_INPUT_STREAM))
+#define GDK_IS_X11_SELECTION_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GDK_TYPE_X11_SELECTION_INPUT_STREAM))
+#define GDK_X11_SELECTION_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GDK_TYPE_X11_SELECTION_INPUT_STREAM, GdkX11SelectionInputStreamClass))
+
+typedef struct GdkX11SelectionInputStream GdkX11SelectionInputStream;
+typedef struct GdkX11SelectionInputStreamClass GdkX11SelectionInputStreamClass;
+
+struct GdkX11SelectionInputStream
+{
+ GInputStream parent_instance;
+};
+
+struct GdkX11SelectionInputStreamClass
+{
+ GInputStreamClass parent_class;
+};
+
+
+GType gdk_x11_selection_input_stream_get_type (void) G_GNUC_CONST;
+
+GInputStream * gdk_x11_selection_input_stream_new (GdkDisplay *display,
+ const char *selection,
+ const char *target);
+
+G_END_DECLS
+
+#endif /* __GDK_X11_SELECTION_INPUT_STREAM_H__ */
diff --git a/gdk/x11/meson.build b/gdk/x11/meson.build
index 526329f..57ed429 100644
--- a/gdk/x11/meson.build
+++ b/gdk/x11/meson.build
@@ -2,6 +2,7 @@
gdk_x11_sources = files([
'gdkapplaunchcontext-x11.c',
'gdkasync.c',
+ 'gdkclipboard-x11.c',
'gdkcursor-x11.c',
'gdkdevice-core-x11.c',
'gdkdevice-xi2.c',
@@ -20,6 +21,7 @@ gdk_x11_sources = files([
'gdkproperty-x11.c',
'gdkscreen-x11.c',
'gdkselection-x11.c',
+ 'gdkselectioninputstream-x11.c',
'gdkvisual-x11.c',
'gdkvulkancontext-x11.c',
'gdkwindow-x11.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]