[gtk+/wip/otte/clipboard: 61/64] x11: Introduce GdkX11PendingSelectionNotify
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/clipboard: 61/64] x11: Introduce GdkX11PendingSelectionNotify
- Date: Fri, 1 Dec 2017 05:27:21 +0000 (UTC)
commit 1d6c2884e253816fb3027e2172936383c58afb9b
Author: Benjamin Otte <otte redhat com>
Date: Fri Dec 1 02:53:47 2017 +0100
x11: Introduce GdkX11PendingSelectionNotify
This object tracks the SelectionNotifyEvent that has to be sent in
response to a SelectionRequest.
Currently it just looks like code reshuffling, but it's a prerequisite
for handling MULTIPLE, which requires to only send the notify after
every stream has writtten at least once.
But anyway, code is cleaner now, so it's a win!
gdk/x11/gdkclipboard-x11.c | 120 +++++++++++---------------
gdk/x11/gdkselectionoutputstream-x11.c | 146 ++++++++++++++++++++++++--------
gdk/x11/gdkselectionoutputstream-x11.h | 14 +++
3 files changed, 175 insertions(+), 105 deletions(-)
---
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
index 3b0aa01..ef11a1b 100644
--- a/gdk/x11/gdkclipboard-x11.c
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -92,8 +92,6 @@ gdk_x11_clipboard_default_output_done (GObject *clipboard,
static void
gdk_x11_clipboard_default_output_handler (GdkX11Clipboard *cb,
const char *target,
- const char *encoding,
- int format,
GOutputStream *stream)
{
gdk_clipboard_write_async (GDK_CLIPBOARD (cb),
@@ -232,7 +230,7 @@ handle_text_list (GdkX11Clipboard *cb,
g_object_unref (converter);
g_object_unref (stream);
- gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", encoding, format,
converter_stream);
+ gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", converter_stream);
}
static void
@@ -242,7 +240,7 @@ handle_utf8 (GdkX11Clipboard *cb,
int format,
GOutputStream *stream)
{
- gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", encoding, format, stream);
+ gdk_x11_clipboard_default_output_handler (cb, "text/plain;charset=utf-8", stream);
}
static GInputStream *
@@ -480,16 +478,15 @@ gdk_x11_clipboard_claim_remote (GdkX11Clipboard *cb,
}
static void
-gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
- Window requestor,
- const char *target,
- const char *property,
- gulong timestamp)
+gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
+ GdkX11PendingSelectionNotify *notify,
+ Window requestor,
+ const char *target,
+ const char *property,
+ gulong timestamp)
{
- const char *type, *mime_type;
- MimeTypeHandleFunc handler_func = NULL;
+ const char *mime_type;
GdkDisplay *display;
- gint format;
gsize i;
display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
@@ -497,9 +494,21 @@ gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
if (mime_type)
{
- handler_func = gdk_x11_clipboard_default_output_handler;
- type = target;
- format = 8;
+ 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);
+ }
}
else
{
@@ -508,65 +517,30 @@ gdk_x11_clipboard_request_selection (GdkX11Clipboard *cb,
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);
- handler_func = special_targets[i].handler;
- type = special_targets[i].type;
- format = special_targets[i].format;
- break;
+ 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;
}
}
}
- if (handler_func == NULL ||
- (mime_type && !gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)),
mime_type)))
- {
- Display *xdisplay = gdk_x11_display_get_xdisplay (display);
- XSelectionEvent xreply;
- int error;
-
- xreply.type = SelectionNotify;
- xreply.serial = 0;
- xreply.send_event = True;
- xreply.requestor = requestor;
- xreply.selection = cb->xselection;
- xreply.target = gdk_x11_get_xatom_by_name_for_display (display, target);
- xreply.property = None;
- xreply.time = timestamp;
-
- GDK_NOTE(CLIPBOARD, g_printerr ("%s%s: Sending SelectionNotify rejecting request\n",
- cb->selection, target));
-
- gdk_x11_display_error_trap_push (display);
- if (XSendEvent (xdisplay, xreply.requestor, False, NoEventMask, (XEvent*) & xreply) == 0)
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("%s:%s: failed to XSendEvent()\n",
- cb->selection, target));
- g_warning ("failed to XSendEvent()");
- }
- XSync (xdisplay, False);
-
- error = gdk_x11_display_error_trap_pop (display);
- if (error != Success)
- {
- GDK_NOTE(CLIPBOARD, g_printerr ("%s:%s: X error during write: %d\n",
- cb->selection, target, error));
- }
- }
- else
- {
- GOutputStream *stream;
-
- stream = gdk_x11_selection_output_stream_new (display,
- requestor,
- cb->selection,
- target,
- property,
- type,
- format,
- timestamp);
- handler_func (cb, target, type, format, stream);
- }
+ gdk_x11_pending_selection_notify_send (notify, display, FALSE);
}
static GdkFilterReturn
@@ -604,6 +578,7 @@ gdk_x11_clipboard_filter_event (GdkXEvent *xev,
case SelectionRequest:
{
+ GdkX11PendingSelectionNotify *notify;
const char *target, *property;
if (xevent->xselectionrequest.selection != cb->xselection)
@@ -630,7 +605,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,
diff --git a/gdk/x11/gdkselectionoutputstream-x11.c b/gdk/x11/gdkselectionoutputstream-x11.c
index 00e6051..5a42421 100644
--- a/gdk/x11/gdkselectionoutputstream-x11.c
+++ b/gdk/x11/gdkselectionoutputstream-x11.c
@@ -29,10 +29,11 @@
#include "gdkx11property.h"
#include "gdkx11window.h"
-typedef struct GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
+typedef struct _GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
-struct GdkX11SelectionOutputStreamPrivate {
+struct _GdkX11SelectionOutputStreamPrivate {
GdkDisplay *display;
+ GdkX11PendingSelectionNotify *notify;
Window xwindow;
char *selection;
Atom xselection;
@@ -52,11 +53,17 @@ struct GdkX11SelectionOutputStreamPrivate {
GTask *pending_task;
- guint started : 1;
guint incr : 1;
guint delete_pending : 1;
};
+struct _GdkX11PendingSelectionNotify
+{
+ gsize n_pending;
+
+ XSelectionEvent xevent;
+};
+
G_DEFINE_TYPE_WITH_PRIVATE (GdkX11SelectionOutputStream, gdk_x11_selection_output_stream,
G_TYPE_OUTPUT_STREAM);
static GdkFilterReturn
@@ -80,7 +87,7 @@ gdk_x11_selection_output_stream_needs_flush_unlocked (GdkX11SelectionOutputStrea
{
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
- if (priv->data->len == 0)
+ if (priv->data->len == 0 && priv->notify == NULL)
return FALSE;
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
@@ -148,7 +155,7 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
element_size = get_element_size (priv->format);
n_elements = priv->data->len / element_size;
- if (!priv->started && !g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
+ if (priv->notify && !g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
{
XWindowAttributes attrs;
@@ -190,30 +197,10 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
priv->flush_requested = FALSE;
}
- if (!priv->started)
+ if (priv->notify)
{
- XSelectionEvent xevent;
-
- xevent.type = SelectionNotify;
- xevent.serial = 0;
- xevent.send_event = True;
- xevent.requestor = priv->xwindow;
- xevent.selection = priv->xselection;
- xevent.target = priv->xtarget;
- xevent.property = priv->xproperty;
- xevent.time = priv->timestamp;
-
- if (XSendEvent (xdisplay, priv->xwindow, False, NoEventMask, (XEvent*) & xevent) == 0)
- {
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: failed to XSendEvent()\n",
- priv->selection, priv->target));
- g_warning ("failed to XSendEvent()");
- }
- XSync (xdisplay, False);
-
- GDK_NOTE(SELECTION, g_printerr ("%s:%s: sent SelectionNotify for %s on %s\n",
- priv->selection, priv->target, priv->target, priv->property));
- priv->started = TRUE;
+ gdk_x11_pending_selection_notify_send (priv->notify, priv->display, TRUE);
+ priv->notify = NULL;
}
priv->delete_pending = TRUE;
@@ -475,6 +462,9 @@ gdk_x11_selection_output_stream_finalize (GObject *object)
GdkX11SelectionOutputStream *stream = GDK_X11_SELECTION_OUTPUT_STREAM (object);
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
+ /* not sending a notify is terrible */
+ g_assert (priv->notify == NULL);
+
g_byte_array_unref (priv->data);
g_cond_clear (&priv->cond);
g_mutex_clear (&priv->mutex);
@@ -550,14 +540,15 @@ gdk_x11_selection_output_stream_filter_event (GdkXEvent *xev,
}
GOutputStream *
-gdk_x11_selection_output_stream_new (GdkDisplay *display,
- Window window,
- const char *selection,
- const char *target,
- const char *property,
- const char *type,
- int format,
- gulong timestamp)
+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)
{
GdkX11SelectionOutputStream *stream;
GdkX11SelectionOutputStreamPrivate *priv;
@@ -567,6 +558,7 @@ gdk_x11_selection_output_stream_new (GdkDisplay *display,
priv->display = display;
GDK_X11_DISPLAY (display)->streams = g_slist_prepend (GDK_X11_DISPLAY (display)->streams, stream);
+ priv->notify = notify;
priv->xwindow = window;
priv->selection = g_strdup (selection);
priv->xselection = gdk_x11_get_xatom_by_name_for_display (display, priv->selection);
@@ -580,6 +572,86 @@ gdk_x11_selection_output_stream_new (GdkDisplay *display,
priv->timestamp = timestamp;
gdk_window_add_filter (NULL, gdk_x11_selection_output_stream_filter_event, stream);
-
+
return G_OUTPUT_STREAM (stream);
}
+
+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;
+}
+
+void
+gdk_x11_pending_selection_notify_require (GdkX11PendingSelectionNotify *notify,
+ guint n_sends)
+{
+ notify->n_pending += n_sends;
+}
+
+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));
+ }
+}
+
+
diff --git a/gdk/x11/gdkselectionoutputstream-x11.h b/gdk/x11/gdkselectionoutputstream-x11.h
index 874d35b..7b4c09c 100644
--- a/gdk/x11/gdkselectionoutputstream-x11.h
+++ b/gdk/x11/gdkselectionoutputstream-x11.h
@@ -36,6 +36,8 @@ 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;
@@ -53,6 +55,7 @@ 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,
@@ -61,6 +64,17 @@ GOutputStream * gdk_x11_selection_output_stream_new (GdkDisplay
int format,
gulong timestamp);
+GdkX11PendingSelectionNotify *
+ gdk_x11_pending_selection_notify_new (Window window,
+ 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);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]