[gtk/wip/carlosg/for-master: 3/3] gtk/main: Keep implicit grab until all buttons are released




commit 43e484887264595049da292148fcf01bc12a1acc
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Dec 8 23:13:50 2020 +0100

    gtk/main: Keep implicit grab until all buttons are released
    
    Currently, the implicit grab is broken on the first button release,
    in the case of pressing multiple buttons simultaneously. This means
    that we emit crossing events early, and the next button releases
    are sent to the pointer focus widget instead.
    
    Consider the implicit grab effective until all buttons are released,
    and only unset the pointer implicit grab (and emit crossing events)
    after there are no further buttons pressed. We do this by checking
    event modifiers, given button release events do contain the modifiers
    in effect at the time the event was generated, we have to look for
    exactly one active button modifier.
    
    Fixes weird pointer states after pressing multiple buttons on a
    widget.
    
    Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3426

 gtk/gtkmain.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index b9d12e19aa..13aa3dd10e 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1375,6 +1375,7 @@ handle_pointing_event (GdkEvent *event)
   GtkWidget *native;
   GdkEventType type;
   gboolean has_implicit;
+  GdkModifierType modifiers;
 
   event_widget = gtk_get_event_widget (event);
   device = gdk_event_get_device (event);
@@ -1480,14 +1481,17 @@ handle_pointing_event (GdkEvent *event)
         gtk_window_lookup_pointer_focus_implicit_grab (toplevel,
                                                        device,
                                                        sequence) != NULL;
+      modifiers = gdk_event_get_modifier_state (event);
 
-      gtk_window_set_pointer_focus_grab (toplevel, device, sequence,
-                                         type == GDK_BUTTON_PRESS ?  target : NULL);
-
-      if (type == GDK_BUTTON_RELEASE)
+      if (type == GDK_BUTTON_RELEASE &&
+          __builtin_popcount (modifiers &
+                              (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
+                               GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)) == 1)
         {
           GtkWidget *new_target = gtk_widget_pick (native, x, y, GTK_PICK_DEFAULT);
 
+          gtk_window_set_pointer_focus_grab (toplevel, device, sequence, NULL);
+
           if (new_target == NULL)
             new_target = GTK_WIDGET (toplevel);
 
@@ -1496,6 +1500,11 @@ handle_pointing_event (GdkEvent *event)
           gtk_window_maybe_update_cursor (toplevel, NULL, device);
           update_pointer_focus_state (toplevel, event, new_target);
         }
+      else if (type == GDK_BUTTON_PRESS)
+        {
+          gtk_window_set_pointer_focus_grab (toplevel, device,
+                                             sequence, target);
+        }
 
       if (type == GDK_BUTTON_PRESS)
         set_widget_active_state (target, FALSE);


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