gtkwindow: Synthesize pointer crossing events on state changes
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 5 Aug 2022 14:39:56 +0000 (16:39 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Fri, 5 Aug 2022 17:25:13 +0000 (19:25 +0200)
When widgets go mapped/unmapped, we repick but don't generate crossing
events. Since there could be stateful controllers that use those in
the previously picked widget (e.g. GtkEventControllerMotion), skipping
those breaks their state.

Ensure to send the relevant crossing events on every situation that
changes the pointer focus, so these controllers get a fair opportunity
to undo their state.

Closes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2877
gtk/gtkwindow.c

index 2c8c5502e8bfdeaed0034669cc2741e0ea542fa6..7d7c4a312bf7fbf01726f5eba1080c680763fded 100644 (file)
@@ -4968,6 +4968,9 @@ synthesize_focus_change_events (GtkWindow       *window,
   GtkWidget *prev;
   gboolean seen_ancestor;
 
+  if (old_focus == new_focus)
+    return;
+
   if (old_focus && new_focus)
     ancestor = gtk_widget_common_ancestor (old_focus, new_focus);
   else
@@ -6455,7 +6458,12 @@ gtk_window_update_pointer_focus_on_state_change (GtkWindow *window,
       else if (focus->target == widget ||
                gtk_widget_is_ancestor (focus->target, widget))
         {
+          GtkWidget *old_target;
+
+          old_target = g_object_ref (focus->target);
           gtk_pointer_focus_repick_target (focus);
+          synthesize_focus_change_events (window, old_target, focus->target, GTK_CROSSING_POINTER);
+          g_object_unref (old_target);
         }
 
       gtk_pointer_focus_unref (focus);