[gtk+] gdkdnd: Add private means to commit the drag status



commit 2923f69d3cc3a3518b847c8d91e5003584cb50f9
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Mar 9 17:00:31 2016 +0100

    gdkdnd: Add private means to commit the drag status
    
    The way gdk_drag_status() may be called multiple times during the
    processing of drag and drop events throughout the widget hierarchy
    brings some superfluous messaging going in, esp. when it's the last
    request the one we want to honor, yet we emit messaging requests on
    all.
    
    This is barely appreciable in the X11 backend, but due to the design
    of the wayland protocol, quick series of changes like this it have
    some self-amplificating consequences which may end up flooding the
    connection.
    
    We can delegate this to a late "commit" call, performed within GDK
    event management. This way gdk_drag_status() calls may be cached
    and only result in windowing messaging once per ::drag-motion or
    ::drag-data-received event. Emitting the final status will also
    avoid spurious action changes on the compositor and the other peer.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=763298

 gdk/gdkdnd.c                 |   50 ++++++++++++++++++++++++++++++++++++++++++
 gdk/gdkdndprivate.h          |    3 ++
 gdk/gdkevents.c              |    3 ++
 gdk/wayland/gdkdnd-wayland.c |    3 +-
 4 files changed, 57 insertions(+), 2 deletions(-)
---
diff --git a/gdk/gdkdnd.c b/gdk/gdkdnd.c
index 02d8d53..3cbd531 100644
--- a/gdk/gdkdnd.c
+++ b/gdk/gdkdnd.c
@@ -764,3 +764,53 @@ gdk_drag_get_cursor (GdkDragAction action)
                                                        drag_cursors[i].name);
   return drag_cursors[i].cursor;
 }
+
+static void
+gdk_drag_context_commit_drag_status (GdkDragContext *context)
+{
+  GdkDragContextClass *context_class;
+
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  g_return_if_fail (!context->is_source);
+
+  context_class = GDK_DRAG_CONTEXT_GET_CLASS (context);
+
+  if (context_class->commit_drag_status)
+    context_class->commit_drag_status (context);
+}
+
+gboolean
+gdk_drag_context_handle_dest_event (GdkEvent *event)
+{
+  GdkDragContext *context = NULL;
+  GList *l;
+
+  switch (event->type)
+    {
+    case GDK_DRAG_MOTION:
+    case GDK_DROP_START:
+      context = event->dnd.context;
+      break;
+    case GDK_SELECTION_NOTIFY:
+      for (l = contexts; l; l = l->next)
+        {
+          GdkDragContext *c = l->data;
+
+          if (!c->is_source &&
+              event->selection.selection == gdk_drag_get_selection (c))
+            {
+              context = c;
+              break;
+            }
+        }
+      break;
+    default:
+      return FALSE;
+    }
+
+  if (!context)
+    return FALSE;
+
+  gdk_drag_context_commit_drag_status (context);
+  return TRUE;;
+}
diff --git a/gdk/gdkdndprivate.h b/gdk/gdkdndprivate.h
index c66de32..283dba2 100644
--- a/gdk/gdkdndprivate.h
+++ b/gdk/gdkdndprivate.h
@@ -84,6 +84,8 @@ struct _GdkDragContextClass {
                                  const GdkEvent  *event);
   void        (*action_changed) (GdkDragContext  *context,
                                  GdkDragAction    action);
+
+  void        (*commit_drag_status) (GdkDragContext  *context);
 };
 
 struct _GdkDragContext {
@@ -116,6 +118,7 @@ void     gdk_drag_context_set_cursor          (GdkDragContext *context,
 void     gdk_drag_context_cancel              (GdkDragContext      *context,
                                                GdkDragCancelReason  reason);
 gboolean gdk_drag_context_handle_source_event (GdkEvent *event);
+gboolean gdk_drag_context_handle_dest_event   (GdkEvent *event);
 GdkCursor * gdk_drag_get_cursor (GdkDragAction action);
 
 G_END_DECLS
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 6a6771c..2eb249e 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -71,6 +71,9 @@ _gdk_event_emit (GdkEvent *event)
 
   if (_gdk_event_func)
     (*_gdk_event_func) (event, _gdk_event_data);
+
+  if (gdk_drag_context_handle_dest_event (event))
+    return;
 }
 
 /*********************************************
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index 1d71d90..2a2bad5 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -287,8 +287,6 @@ gdk_wayland_drag_context_drag_status (GdkDragContext *context,
 
   wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
   wayland_context->selected_action = action;
-
-  gdk_wayland_drag_context_commit_status (context);
 }
 
 static void
@@ -471,6 +469,7 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
   context_class->action_changed = gdk_wayland_drag_context_action_changed;
   context_class->drop_performed = gdk_wayland_drag_context_drop_performed;
   context_class->cancel = gdk_wayland_drag_context_cancel;
+  context_class->commit_drag_status = gdk_wayland_drag_context_commit_status;
 }
 
 GdkDragProtocol


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]