[gimp] app: compress tool motion evnets more conservatively



commit 5543a9da4f168c2c30ff06d358f8f48f3a250b88
Author: Ell <ell_se yahoo com>
Date:   Sun Jun 11 14:45:36 2017 -0400

    app: compress tool motion evnets more conservatively
    
    When compressing tool motion events, only compress motion events
    at the front of the event queue, targeted at the same widget as,
    and having similar characteristics to, the initial motion event;
    stop compressing upon the first mismatched event.
    
    Previously, all pending motion events targeted at the canvas were
    compressed, stopping only at a button-release event targeted at the
    canvas.  As a result, when adding a guide by dragging from a ruler,
    there could be a situation where a pending button-release event
    targeted at the ruler would be followed by motion events targeted at
    the canvas, with a cleared state mask.  These motion events would
    get compressed to the initial motion event targeted at the ruler,
    resulting in a motion event with a cleared state mask being processed
    before the said button-release event.  This, in turn, would cause the
    guide tool's cursor_update function to be called, while the tool is
    still active, emitting a CRITICAL.  Sheesh.
    
    The moral of the story is: let's play it safe.

 app/display/gimpdisplayshell-tool-events.c |   59 +++++++++------------------
 1 files changed, 20 insertions(+), 39 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-tool-events.c b/app/display/gimpdisplayshell-tool-events.c
index 3c59e25..d08ed13 100644
--- a/app/display/gimpdisplayshell-tool-events.c
+++ b/app/display/gimpdisplayshell-tool-events.c
@@ -126,7 +126,7 @@ static void       gimp_display_shell_untransform_event_coords (GimpDisplayShell
                                                                GimpCoords        *image_coords,
                                                                gboolean          *update_software_cursor);
 
-static GdkEvent * gimp_display_shell_compress_motion          (GimpDisplayShell  *shell);
+static GdkEvent * gimp_display_shell_compress_motion          (GdkEvent          *initial_event);
 
 
 /*  public functions  */
@@ -851,7 +851,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget        *canvas,
         if (shell->scrolling ||
             motion_mode == GIMP_MOTION_MODE_COMPRESS)
           {
-            compressed_motion = gimp_display_shell_compress_motion (shell);
+            compressed_motion = gimp_display_shell_compress_motion (event);
 
             if (compressed_motion && ! shell->scrolling)
               {
@@ -1946,8 +1946,9 @@ gimp_display_shell_untransform_event_coords (GimpDisplayShell *shell,
 
 /* gimp_display_shell_compress_motion:
  *
- * This function walks the whole GDK event queue seeking motion events
- * corresponding to the widget 'widget'.  If it finds any it will
+ * This function walks the GDK event queue, seeking motion events at the
+ * front of the queue corresponding to the same widget as, and having
+ * similar characteristics to, `initial_event`.   If it finds any it will
  * remove them from the queue, and return the most recent motion event.
  * Otherwise it will return NULL.
  *
@@ -1955,15 +1956,16 @@ gimp_display_shell_untransform_event_coords (GimpDisplayShell *shell,
  * the XFree86-style license. <adam gimp org>
  */
 static GdkEvent *
-gimp_display_shell_compress_motion (GimpDisplayShell *shell)
+gimp_display_shell_compress_motion (GdkEvent *initial_event)
 {
-  GList       *requeued_events = NULL;
-  const GList *list;
-  GdkEvent    *last_motion = NULL;
+  GdkEvent  *last_motion = NULL;
+  GtkWidget *widget;
+
+  if (initial_event->any.type != GDK_MOTION_NOTIFY)
+    return NULL;
+
+  widget = gtk_get_event_widget (initial_event);
 
-  /*  Move the entire GDK event queue to a private list, filtering
-   *  out any motion events for the desired widget.
-   */
   while (gdk_events_pending ())
     {
       GdkEvent *event = gdk_event_get ();
@@ -1972,45 +1974,24 @@ gimp_display_shell_compress_motion (GimpDisplayShell *shell)
         {
           /* Do nothing */
         }
-      else if ((gtk_get_event_widget (event) == shell->canvas) &&
-               (event->any.type == GDK_MOTION_NOTIFY))
+      else if ((gtk_get_event_widget (event) == widget)               &&
+               (event->any.type      == GDK_MOTION_NOTIFY)            &&
+               (event->motion.state  == initial_event->motion.state)  &&
+               (event->motion.device == initial_event->motion.device))
         {
           if (last_motion)
             gdk_event_free (last_motion);
 
           last_motion = event;
         }
-      else if ((gtk_get_event_widget (event) == shell->canvas) &&
-               (event->any.type == GDK_BUTTON_RELEASE))
+      else
         {
-          requeued_events = g_list_prepend (requeued_events, event);
-
-          while (gdk_events_pending ())
-            if ((event = gdk_event_get ()))
-              requeued_events = g_list_prepend (requeued_events, event);
+          gdk_event_put (event);
+          gdk_event_free (event);
 
           break;
         }
-      else
-        {
-          requeued_events = g_list_prepend (requeued_events, event);
-        }
     }
 
-  /* Replay the remains of our private event list back into the
-   * event queue in order.
-   */
-  requeued_events = g_list_reverse (requeued_events);
-
-  for (list = requeued_events; list; list = g_list_next (list))
-    {
-      GdkEvent *event = list->data;
-
-      gdk_event_put (event);
-      gdk_event_free (event);
-    }
-
-  g_list_free (requeued_events);
-
   return last_motion;
 }


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