From 12170acf464ab203e7a6a099ae7334de070d19e9 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 30 Jul 2020 13:21:28 -0400 Subject: [PATCH 1/3] Define GTK_CROSSING_ACTIVE Document the different crossing event kinds that we use, and add GTK_CROSSING_ACTIVE. We are going to use it in the future when the active window changes. --- gtk/gtkeventcontrollerprivate.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/gtk/gtkeventcontrollerprivate.h b/gtk/gtkeventcontrollerprivate.h index c997f7951e..e639e2d82a 100644 --- a/gtk/gtkeventcontrollerprivate.h +++ b/gtk/gtkeventcontrollerprivate.h @@ -22,12 +22,29 @@ #include "gtkeventcontroller.h" +/* GdkCrossingType: + * @GTK_CROSSING_FOCUS: Focus moved from one widget to another + * @GTK_CROSSING_ACTIVE: The active window changed (the crossing + * events in this case leave from the old active window's focus + * location to the new active window's one. + * @GTK_CROSSING_POINTER: The pointer moved from one widget to another + * @GTK_CROSSING_POINTER: An active drag moved from one widget to another + * + * We emit various kinds of crossing events when the target widget + * for keyboard or pointer events changes. + */ typedef enum { GTK_CROSSING_FOCUS, + GTK_CROSSING_ACTIVE, GTK_CROSSING_POINTER, GTK_CROSSING_DROP } GtkCrossingType; +/* + * GdkCrossingirection: + * @GTK_CROSSING_IN: the event is on the downward slope, towards the new target + * @GTK_CROSSING_OUT: the event is on the upward slope, away from the old target + */ typedef enum { GTK_CROSSING_IN, GTK_CROSSING_OUT From b0d40403e1063a0ab24d715e45680a112b19cbc6 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 30 Jul 2020 13:22:26 -0400 Subject: [PATCH 2/3] window: Emit GTK_CROSSING_ACTIVE crossing events Emit crossing events when the active window changes. We don't want to emit GTK_CROSSING_FOCUS events, since every window has its own focus location (focus does not jump from window to window), so we use the new GTK_CROSSING_ACTIVE type of crossing event for this. --- gtk/gtkwindow.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index fc9723431e..c9da4da3d2 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1834,9 +1834,10 @@ gtk_window_root_get_focus (GtkRoot *root) return priv->focus_widget; } -static void synthesize_focus_change_events (GtkWindow *window, - GtkWidget *old_focus, - GtkWidget *new_focus); +static void synthesize_focus_change_events (GtkWindow *window, + GtkWidget *old_focus, + GtkWidget *new_focus, + GtkCrossingType type); static void gtk_window_root_set_focus (GtkRoot *root, @@ -1859,7 +1860,7 @@ gtk_window_root_set_focus (GtkRoot *root, if (old_focus) gtk_widget_set_has_focus (old_focus, FALSE); - synthesize_focus_change_events (self, old_focus, focus); + synthesize_focus_change_events (self, old_focus, focus, GTK_CROSSING_FOCUS); if (focus) gtk_widget_set_has_focus (focus, TRUE); @@ -4984,9 +4985,10 @@ check_crossing_invariants (GtkWidget *widget, } static void -synthesize_focus_change_events (GtkWindow *window, - GtkWidget *old_focus, - GtkWidget *new_focus) +synthesize_focus_change_events (GtkWindow *window, + GtkWidget *old_focus, + GtkWidget *new_focus, + GtkCrossingType type) { GtkCrossingData crossing; GtkWidget *ancestor; @@ -5005,7 +5007,7 @@ synthesize_focus_change_events (GtkWindow *window, if (gtk_window_get_focus_visible (GTK_WINDOW (window))) flags |= GTK_STATE_FLAG_FOCUS_VISIBLE; - crossing.type = GTK_CROSSING_FOCUS; + crossing.type = type; crossing.mode = GDK_CROSSING_NORMAL; crossing.old_target = old_focus; crossing.old_descendent = NULL; @@ -5038,7 +5040,7 @@ synthesize_focus_change_events (GtkWindow *window, { crossing.new_descendent = NULL; } - + check_crossing_invariants (widget, &crossing); gtk_widget_handle_crossing (widget, &crossing, 0, 0); gtk_widget_unset_state_flags (widget, flags); @@ -6303,14 +6305,14 @@ gtk_window_keys_changed (GtkWindow *window) * _gtk_window_set_is_active: * @window: a #GtkWindow * @is_active: %TRUE if the window is in the currently active toplevel - * + * * Internal function that sets whether the #GtkWindow is part * of the currently active toplevel window (taking into account inter-process * embedding.) **/ static void _gtk_window_set_is_active (GtkWindow *window, - gboolean is_active) + gboolean is_active) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); @@ -6319,6 +6321,20 @@ _gtk_window_set_is_active (GtkWindow *window, priv->is_active = is_active; + if (priv->focus_widget) + { + GtkWidget *focus; + + focus = g_object_ref (priv->focus_widget); + + if (is_active) + synthesize_focus_change_events (window, NULL, focus, GTK_CROSSING_ACTIVE); + else + synthesize_focus_change_events (window, focus, NULL, GTK_CROSSING_ACTIVE); + + g_object_unref (focus); + } + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_IS_ACTIVE]); } From 643d873f47f4f45d660759e9814254fce680d1f6 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 30 Jul 2020 13:23:45 -0400 Subject: [PATCH 3/3] eventcontrollerkey: Update im focus when active window changes Use the new GTK_CROSSING_ACTIVE crossing events to update the im context focus when the window becomes active or inactive. IBus requires this, since it has only a single, global focus location. Fixes: #2390 --- gtk/gtkeventcontrollerkey.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c index e813654be8..4d8774b425 100644 --- a/gtk/gtkeventcontrollerkey.c +++ b/gtk/gtkeventcontrollerkey.c @@ -154,7 +154,8 @@ gtk_event_controller_key_handle_crossing (GtkEventController *controller, gboolean start_crossing, end_crossing; gboolean is_focus; - if (crossing->type != GTK_CROSSING_FOCUS) + if (crossing->type != GTK_CROSSING_FOCUS && + crossing->type != GTK_CROSSING_ACTIVE) return; start_crossing = crossing->direction == GTK_CROSSING_OUT &&