gtkmain: Disable implicit grab active state on CROSSING_GRAB leave events
authorCarlos Garnacho <carlosg@gnome.org>
Tue, 16 Nov 2021 09:52:35 +0000 (10:52 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 16 Nov 2021 09:58:03 +0000 (10:58 +0100)
This grab-induced crossing event may come from outer means while there are
buttons pressed (e.g. WM window drags/resizes in X11), the implicit active
state should be undone in that situation.

Also, separate the handling of GDK_LEAVE_NOTIFY, as it's fundamentally
different from GDK_TOUCH_END/CANCEL handling.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/4416
gtk/gtkmain.c

index 4c49be49d5cd496e735c93c0b5df92cc2ac77acf..bb25aaca63b07365289291e9e558d61f8184f450 100644 (file)
@@ -1345,14 +1345,26 @@ handle_pointing_event (GdkEvent *event)
   switch ((guint) type)
     {
     case GDK_LEAVE_NOTIFY:
+      if (gdk_crossing_event_get_mode (event) == GDK_CROSSING_GRAB)
+        {
+          GtkWidget *grab_widget;
+
+          grab_widget =
+            gtk_window_lookup_pointer_focus_implicit_grab (toplevel,
+                                                           device,
+                                                           sequence);
+          if (grab_widget)
+            set_widget_active_state (grab_widget, FALSE);
+        }
+
+      old_target = update_pointer_focus_state (toplevel, event, NULL);
+      gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, old_target, NULL,
+                                      event, gdk_crossing_event_get_mode (event), NULL);
+      break;
     case GDK_TOUCH_END:
     case GDK_TOUCH_CANCEL:
       old_target = update_pointer_focus_state (toplevel, event, NULL);
-      if (type == GDK_TOUCH_END || type == GDK_TOUCH_CANCEL)
-        set_widget_active_state (old_target, FALSE);
-      else if (type == GDK_LEAVE_NOTIFY)
-        gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, old_target, NULL,
-                                        event, gdk_crossing_event_get_mode (event), NULL);
+      set_widget_active_state (old_target, FALSE);
       break;
     case GDK_DRAG_LEAVE:
       {