[gtk+/wip/otte/clipboard: 61/64] x11: Introduce GdkX11PendingSelectionNotify



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*) &notify->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]