[gtk/readonly-events-1: 111/149] New focus change handling
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/readonly-events-1: 111/149] New focus change handling
- Date: Fri, 21 Feb 2020 05:58:34 +0000 (UTC)
commit 23c67f8c672ee3c0a3e22afd71ac86f96592dca5
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Feb 12 20:26:29 2020 -0500
New focus change handling
Instead of relying on gdk's antiquated crossing events,
create a new GtkCrossingData struct that contains the
actual widgets, and a new event controller vfunc that
expects this struct. This also saves us from making sense
of X's crossing modes and details, and makes for a
generally simpler api.
The ::focus-in and ::focus-out signals of GtkEventControllerKey
have been replaced by a single ::focus-change signal that
takes GtkCrossingData as an argument. All callers have
been updated.
gtk/gtkcalendar.c | 17 ++--
gtk/gtkentrycompletion.c | 14 +--
gtk/gtkenums.h | 10 ++
gtk/gtkeventcontroller.c | 67 ++++++++++++
gtk/gtkeventcontroller.h | 35 +++++++
gtk/gtkeventcontrollerkey.c | 221 +++++++++++++++-------------------------
gtk/gtkeventcontrollerprivate.h | 5 +
gtk/gtkfilechooserentry.c | 12 +--
gtk/gtkmodelbutton.c | 20 ++--
gtk/gtkpopover.c | 13 ---
gtk/gtkpopovermenu.c | 12 +--
gtk/gtkspinbutton.c | 14 +--
gtk/gtktext.c | 74 +++++++-------
gtk/gtktextview.c | 108 +++++++++-----------
gtk/gtktreeview.c | 37 +++----
gtk/gtktreeviewcolumn.c | 8 +-
gtk/gtkwidget.c | 21 ++++
gtk/gtkwidgetprivate.h | 4 +
gtk/gtkwindow.c | 119 +++++++++++++++-------
19 files changed, 456 insertions(+), 355 deletions(-)
---
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 1c97018c2d..36470a711d 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -280,9 +280,8 @@ static gboolean gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *
guint keycode,
GdkModifierType state,
GtkWidget *widget);
-static void gtk_calendar_key_controller_focus (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
+static void gtk_calendar_key_controller_focus (GtkEventController *controller,
+ GtkCrossingDirection direction,
GtkWidget *widget);
static void gtk_calendar_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
@@ -593,10 +592,7 @@ gtk_calendar_init (GtkCalendar *calendar)
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_calendar_key_controller_key_pressed),
calendar);
- g_signal_connect (controller, "focus-in",
- G_CALLBACK (gtk_calendar_key_controller_focus),
- calendar);
- g_signal_connect (controller, "focus-out",
+ g_signal_connect (controller, "focus-change",
G_CALLBACK (gtk_calendar_key_controller_focus),
calendar);
gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
@@ -1393,10 +1389,9 @@ gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
-gtk_calendar_key_controller_focus (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkWidget *widget)
+gtk_calendar_key_controller_focus (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkWidget *widget)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c
index c5a95c9748..4167b7e104 100644
--- a/gtk/gtkentrycompletion.c
+++ b/gtk/gtkentrycompletion.c
@@ -2307,13 +2307,13 @@ accept_completion_callback (GtkEntryCompletion *completion)
return FALSE;
}
-static gboolean
-text_focus_out (GtkEntryCompletion *completion)
+static void
+text_focus_change (GtkEntryCompletion *completion,
+ GtkCrossingDirection direction)
{
- if (gtk_widget_get_mapped (completion->priv->popup_window))
- return FALSE;
-
- return accept_completion_callback (completion);
+ if (direction == GTK_CROSSING_OUT &&
+ !gtk_widget_get_mapped (completion->priv->popup_window))
+ accept_completion_callback (completion);
}
static void
@@ -2349,7 +2349,7 @@ connect_completion_signals (GtkEntryCompletion *completion)
controller = priv->entry_key_controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_entry_completion_key_pressed), completion);
- g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (text_focus_out), completion);
+ g_signal_connect_swapped (controller, "focus-change", G_CALLBACK (text_focus_change), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
completion->priv->changed_id =
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index d4c3b4de2b..59eb3e17c6 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -954,6 +954,16 @@ typedef enum
GTK_EVENT_SEQUENCE_DENIED
} GtkEventSequenceState;
+typedef enum {
+ GTK_CROSSING_FOCUS,
+ GTK_CROSSING_POINTER
+} GtkCrossingType;
+
+typedef enum {
+ GTK_CROSSING_IN,
+ GTK_CROSSING_OUT
+} GtkCrossingDirection;
+
/**
* GtkPanDirection:
* @GTK_PAN_DIRECTION_LEFT: panned towards the left
diff --git a/gtk/gtkeventcontroller.c b/gtk/gtkeventcontroller.c
index f67669d18d..9c77d49444 100644
--- a/gtk/gtkeventcontroller.c
+++ b/gtk/gtkeventcontroller.c
@@ -127,6 +127,14 @@ gtk_event_controller_handle_event_default (GtkEventController *self,
return FALSE;
}
+static void
+gtk_event_controller_handle_crossing_default (GtkEventController *self,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+}
+
static void
gtk_event_controller_set_property (GObject *object,
guint prop_id,
@@ -204,6 +212,7 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
klass->unset_widget = gtk_event_controller_unset_widget;
klass->filter_event = gtk_event_controller_filter_event_default;
klass->handle_event = gtk_event_controller_handle_event_default;
+ klass->handle_crossing = gtk_event_controller_handle_crossing_default;
object_class->finalize = gtk_event_controller_finalize;
object_class->set_property = gtk_event_controller_set_property;
@@ -307,6 +316,34 @@ gtk_event_controller_handle_event (GtkEventController *controller,
return retval;
}
+/**
+ * gtk_event_controller_handle_crossing:
+ * @controller: a #GtkEventController
+ * @crossing: a #GtkCrossingData
+ * @x: event position in widget coordinates
+ * @y: event position in widget coordinates
+ *
+ * Feeds a crossing event into @controller, so it can be interpreted
+ * and the controller actions triggered.
+ **/
+void
+gtk_event_controller_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkEventControllerClass *controller_class;
+
+ g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
+ g_return_if_fail (crossing != NULL);
+
+ controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
+
+ g_object_ref (controller);
+ controller_class->handle_crossing (controller, crossing, x, y);
+ g_object_unref (controller);
+}
+
/**
* gtk_event_controller_get_widget:
* @controller: a #GtkEventController
@@ -451,3 +488,33 @@ gtk_event_controller_set_name (GtkEventController *controller,
g_free (priv->name);
priv->name = g_strdup (name);
}
+
+static GtkCrossingData *
+gtk_crossing_data_copy (GtkCrossingData *crossing)
+{
+ GtkCrossingData *copy;
+
+ copy = g_new (GtkCrossingData, 1);
+
+ copy->type = crossing->type;
+ copy->direction = crossing->direction;
+
+ if (crossing->old_target)
+ copy->old_target = g_object_ref (crossing->old_target);
+ if (crossing->new_target)
+ copy->new_target = g_object_ref (crossing->new_target);
+
+ return copy;
+}
+
+static void
+gtk_crossing_data_free (GtkCrossingData *crossing)
+{
+ g_clear_object (&crossing->old_target);
+ g_clear_object (&crossing->new_target);
+
+ g_free (crossing);
+}
+
+G_DEFINE_BOXED_TYPE (GtkCrossingData, gtk_crossing_data,
+ gtk_crossing_data_copy, gtk_crossing_data_free)
diff --git a/gtk/gtkeventcontroller.h b/gtk/gtkeventcontroller.h
index 1f058fb11b..b4694a5f7b 100644
--- a/gtk/gtkeventcontroller.h
+++ b/gtk/gtkeventcontroller.h
@@ -40,6 +40,36 @@ G_BEGIN_DECLS
#define GTK_EVENT_CONTROLLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER,
GtkEventControllerClass))
+typedef struct _GtkCrossingData GtkCrossingData;
+
+/**
+ * GtkCrossingData:
+ * @type: the type of crossing event
+ * @direction: whether this is a focus-in or focus-out event
+ * @mode: the crossing mode
+ * @old_target: the old target
+ * @new_target: the new target
+ *
+ * The struct that is passed to gtk_event_controller_handle_crossing()
+ * and is also passed to #GtkEventControllerKey::focus-change.
+ *
+ * The @old_target and @new_target fields are set to the old or new
+ * focus or hover location.
+ */
+struct _GtkCrossingData {
+ GtkCrossingType type;
+ GtkCrossingDirection direction;
+ GdkCrossingMode mode;
+ GtkWidget *old_target;
+ GtkWidget *new_target;
+};
+
+#define GTK_TYPE_CROSSING_DATA (gtk_crossing_data_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_crossing_data_get_type (void) G_GNUC_CONST;
+
+
GDK_AVAILABLE_IN_ALL
GType gtk_event_controller_get_type (void) G_GNUC_CONST;
@@ -52,6 +82,11 @@ gboolean gtk_event_controller_handle_event (GtkEventController *controller
double x,
double y);
GDK_AVAILABLE_IN_ALL
+void gtk_event_controller_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
+GDK_AVAILABLE_IN_ALL
void gtk_event_controller_reset (GtkEventController *controller);
GDK_AVAILABLE_IN_ALL
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index 0085e636f9..47890a4aee 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -38,6 +38,7 @@
#include "gtkbindings.h"
#include "gtkenums.h"
#include "gtkmain.h"
+#include "gtktypebuiltins.h"
#include <gdk/gdk.h>
@@ -50,6 +51,7 @@ struct _GtkEventControllerKey
GdkModifierType state;
const GdkEvent *current_event;
+ const GtkCrossingData *current_crossing;
guint is_focus : 1;
guint contains_focus : 1;
@@ -65,8 +67,7 @@ enum {
KEY_RELEASED,
MODIFIERS,
IM_UPDATE,
- FOCUS_IN,
- FOCUS_OUT,
+ FOCUS_CHANGE,
N_SIGNALS
};
@@ -94,57 +95,6 @@ gtk_event_controller_key_finalize (GObject *object)
G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
}
-static void
-update_focus (GtkEventControllerKey *key,
- gboolean focus_in,
- GdkNotifyType detail)
-{
- gboolean is_focus;
- gboolean contains_focus;
-
- switch (detail)
- {
- case GDK_NOTIFY_VIRTUAL:
- case GDK_NOTIFY_NONLINEAR_VIRTUAL:
- is_focus = FALSE;
- contains_focus = focus_in;
- break;
- case GDK_NOTIFY_ANCESTOR:
- case GDK_NOTIFY_NONLINEAR:
- is_focus = focus_in;
- contains_focus = is_focus;
- break;
- case GDK_NOTIFY_INFERIOR:
- is_focus = focus_in;
- contains_focus = TRUE;
- break;
- case GDK_NOTIFY_UNKNOWN:
- default:
- g_warning ("Unknown focus change detail");
- return;
- }
-
- g_object_freeze_notify (G_OBJECT (key));
- if (key->is_focus != is_focus)
- {
- key->is_focus = is_focus;
- g_object_notify (G_OBJECT (key), "is-focus");
- if (key->im_context)
- {
- if (focus_in)
- gtk_im_context_focus_in (key->im_context);
- else
- gtk_im_context_focus_out (key->im_context);
- }
- }
- if (key->contains_focus != contains_focus)
- {
- key->contains_focus = contains_focus;
- g_object_notify (G_OBJECT (key), "contains-focus");
- }
- g_object_thaw_notify (G_OBJECT (key));
-}
-
static gboolean
gtk_event_controller_key_handle_event (GtkEventController *controller,
const GdkEvent *event,
@@ -158,30 +108,6 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
guint keyval;
gboolean handled = FALSE;
- if (event_type == GDK_FOCUS_CHANGE)
- {
- gboolean focus_in;
- GdkCrossingMode mode;
- GdkNotifyType detail;
-
- gdk_event_get_focus_in (event, &focus_in);
- gdk_event_get_crossing_mode (event, &mode);
- gdk_event_get_crossing_detail (event, &detail);
-
- update_focus (key, focus_in, detail);
-
- key->current_event = event;
-
- if (focus_in)
- g_signal_emit (controller, signals[FOCUS_IN], 0, mode, detail);
- else
- g_signal_emit (controller, signals[FOCUS_OUT], 0, mode, detail);
-
- key->current_event = NULL;
-
- return FALSE;
- }
-
if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
return FALSE;
@@ -229,6 +155,64 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
return handled;
}
+static void
+update_focus (GtkEventController *controller,
+ const GtkCrossingData *crossing)
+{
+ GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ gboolean is_focus = FALSE;
+ gboolean contains_focus = FALSE;
+
+ if (crossing->direction == GTK_CROSSING_IN)
+ {
+ if (crossing->new_target == widget)
+ is_focus = TRUE;
+ if (crossing->new_target != NULL)
+ contains_focus = TRUE;
+ }
+
+ g_object_freeze_notify (G_OBJECT (key));
+ if (key->is_focus != is_focus)
+ {
+ key->is_focus = is_focus;
+ g_object_notify (G_OBJECT (key), "is-focus");
+ if (key->im_context)
+ {
+ if (is_focus)
+ gtk_im_context_focus_in (key->im_context);
+ else
+ gtk_im_context_focus_out (key->im_context);
+ }
+ }
+ if (key->contains_focus != contains_focus)
+ {
+ key->contains_focus = contains_focus;
+ g_object_notify (G_OBJECT (key), "contains-focus");
+ }
+ g_object_thaw_notify (G_OBJECT (key));
+}
+
+static void
+gtk_event_controller_key_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
+
+ if (crossing->type != GTK_CROSSING_FOCUS)
+ return;
+
+ key->current_crossing = crossing;
+
+ update_focus (controller, crossing);
+
+ g_signal_emit (controller, signals[FOCUS_CHANGE], 0, crossing->direction);
+
+ key->current_crossing = NULL;
+}
+
static void
gtk_event_controller_key_get_property (GObject *object,
guint prop_id,
@@ -261,6 +245,7 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
object_class->finalize = gtk_event_controller_key_finalize;
object_class->get_property = gtk_event_controller_key_get_property;
controller_class->handle_event = gtk_event_controller_key_handle_event;
+ controller_class->handle_crossing = gtk_event_controller_key_handle_crossing;
/**
* GtkEventControllerKey:is-focus:
@@ -366,7 +351,7 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
/**
* GtkEventControllerKey::im-update:
- * @controller: the object which received the signal.
+ * @controller: the object which received the signal
*
* This signal is emitted whenever the input method context filters away a
* keypress and prevents the @controller receiving it. See
@@ -382,46 +367,27 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
G_TYPE_NONE, 0);
/**
- * GtkEventControllerKey::focus-in:
- * @controller: the object which received the signal.
- * @mode: crossing mode indicating what caused this change
- * @detail: detail indication where the focus is coming from
+ * GtkEventControllerKey::focus-change:
+ * @controller: the object which received the signal
+ * @direction: the direction of this crossing event
*
- * This signal is emitted whenever the widget controlled
- * by the @controller or one of its descendants) is given
- * the keyboard focus.
- */
- signals[FOCUS_IN] =
- g_signal_new (I_("focus-in"),
- GTK_TYPE_EVENT_CONTROLLER_KEY,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 2,
- GDK_TYPE_CROSSING_MODE,
- GDK_TYPE_NOTIFY_TYPE);
-
- /**
- * GtkEventControllerKey::focus-out:
- * @controller: the object which received the signal.
- * @mode: crossing mode indicating what caused this change
- * @detail: detail indication where the focus is going
+ * This signal is emitted whenever the focus change from or
+ * to a widget that is a descendant of the widget to which
+ * @controller is attached.
*
- * This signal is emitted whenever the widget controlled
- * by the @controller (or one of its descendants) loses
- * the keyboard focus.
+ * Handlers for this signal can use
+ * gtk_event_controller_key_get_focus_origin() and
+ * gtk_event_controller_key_get_focus_target() to find
+ * the old and new focus locations.
*/
- signals[FOCUS_OUT] =
- g_signal_new (I_("focus-out"),
+ signals[FOCUS_CHANGE] =
+ g_signal_new (I_("focus-change"),
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
- G_TYPE_NONE,
- 2,
- GDK_TYPE_CROSSING_MODE,
- GDK_TYPE_NOTIFY_TYPE);
+ G_TYPE_NONE, 1,
+ GTK_TYPE_CROSSING_DIRECTION);
}
static void
@@ -553,29 +519,17 @@ gtk_event_controller_key_get_group (GtkEventControllerKey *controller)
* Returns the widget that was holding focus before.
*
* This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-in and
- * #GtkEventControllerKey::focus-out signals.
+ * #GtkEventControllerKey::focus-changed signal.
*
* Returns: (transfer none): the previous focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
{
- gboolean focus_in;
- GtkWidget *origin;
-
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_event != NULL, NULL);
- g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
-
- gdk_event_get_focus_in (controller->current_event, &focus_in);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
- if (focus_in)
- origin = (GtkWidget *)gdk_event_get_related_target (controller->current_event);
- else
- origin = (GtkWidget *)gdk_event_get_target (controller->current_event);
-
- return origin;
+ return controller->current_crossing->old_target;
}
/**
@@ -585,26 +539,17 @@ gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
* Returns the widget that will be holding focus afterwards.
*
* This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-in and
- * #GtkEventControllerKey::focus-out signals.
+ * #GtkEventControllerKey::focus-changed signal.
*
* Returns: (transfer none): the next focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
{
- gboolean focus_in;
-
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_event != NULL, NULL);
- g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
- gdk_event_get_focus_in (controller->current_event, &focus_in);
-
- if (focus_in)
- return (GtkWidget *)gdk_event_get_target (controller->current_event);
- else
- return (GtkWidget *)gdk_event_get_related_target (controller->current_event);
+ return controller->current_crossing->new_target;
}
/**
diff --git a/gtk/gtkeventcontrollerprivate.h b/gtk/gtkeventcontrollerprivate.h
index 354956f841..aed93f311a 100644
--- a/gtk/gtkeventcontrollerprivate.h
+++ b/gtk/gtkeventcontrollerprivate.h
@@ -40,6 +40,11 @@ struct _GtkEventControllerClass
double y);
void (* reset) (GtkEventController *controller);
+ void (* handle_crossing) (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
+
/*<private>*/
/* Tells whether the event is filtered out, %TRUE makes
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 2c8a73f0c8..9123bddb91 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -259,12 +259,12 @@ match_func (GtkEntryCompletion *compl,
}
static void
-chooser_entry_focus_out (GtkEventControllerKey *key_controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkFileChooserEntry *chooser_entry)
+chooser_entry_focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkFileChooserEntry *chooser_entry)
{
- set_complete_on_load (chooser_entry, FALSE);
+ if (direction == GTK_CROSSING_OUT)
+ set_complete_on_load (chooser_entry, FALSE);
}
static void
@@ -312,7 +312,7 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
G_CALLBACK (gtk_file_chooser_entry_tab_handler),
chooser_entry);
g_signal_connect (controller,
- "focus-out", G_CALLBACK (chooser_entry_focus_out),
+ "focus-change", G_CALLBACK (chooser_entry_focus_change),
chooser_entry);
gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index 5545ed95df..7744c6cfdd 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -1359,19 +1359,21 @@ leave_cb (GtkEventController *controller,
}
static void
-focus_in_cb (GtkEventController *controller,
- GdkCrossingMode mode,
- GdkNotifyType type,
- gpointer data)
+focus_change_cb (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
- target = gtk_event_controller_get_widget (controller);
- popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
+ if (direction == GTK_CROSSING_IN)
+ {
+ target = gtk_event_controller_get_widget (controller);
+ popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
- if (popover)
- gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
+ if (popover)
+ gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
+ }
}
static void
@@ -1400,7 +1402,7 @@ gtk_model_button_init (GtkModelButton *self)
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in_cb), NULL);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
gesture = gtk_gesture_click_new ();
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index a5285a2766..c2e4d8ee23 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -563,17 +563,6 @@ gtk_popover_native_check_resize (GtkNative *native)
present_popup (popover);
}
-
-static void
-gtk_popover_focus_in (GtkWidget *widget)
-{
-}
-
-static void
-gtk_popover_focus_out (GtkWidget *widget)
-{
-}
-
static void
close_menu (GtkPopover *popover)
{
@@ -727,8 +716,6 @@ gtk_popover_init (GtkPopover *popover)
priv->has_arrow = TRUE;
controller = gtk_event_controller_key_new ();
- g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popover_focus_in), popover);
- g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (gtk_popover_focus_out), popover);
g_signal_connect_swapped (controller, "key-pressed", G_CALLBACK (gtk_popover_key_pressed), popover);
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index bf56b4c5be..7e99902e6b 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -168,14 +168,14 @@ visible_submenu_changed (GObject *object,
}
static void
-focus_out (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkPopoverMenu *menu)
+focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkPopoverMenu *menu)
{
GtkWidget *new_focus = gtk_root_get_focus (gtk_widget_get_root (GTK_WIDGET (menu)));
- if (!gtk_event_controller_key_contains_focus (controller) &&
+ if (direction == GTK_CROSSING_OUT &&
+ !gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (controller)) &&
new_focus != NULL)
{
if (menu->parent_menu &&
@@ -216,7 +216,7 @@ gtk_popover_menu_init (GtkPopoverMenu *popover)
gtk_widget_add_css_class (GTK_WIDGET (popover), "menu");
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-out", G_CALLBACK (focus_out), popover);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change), popover);
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
controller = gtk_event_controller_motion_new ();
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index bef3c0b49f..284041d168 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -917,14 +917,14 @@ key_controller_key_released (GtkEventControllerKey *key,
}
static void
-key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkSpinButton *spin_button)
+key_controller_focus_change (GtkEventController *controller,
+ GtkCrossingDirection direction,
+ GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin_button);
- if (gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
+ if (direction == GTK_CROSSING_OUT &&
+ gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
gtk_spin_button_update (spin_button);
}
@@ -1012,8 +1012,8 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-released",
G_CALLBACK (key_controller_key_released), spin_button);
- g_signal_connect (controller, "focus-out",
- G_CALLBACK (key_controller_focus_out), spin_button);
+ g_signal_connect (controller, "focus-change",
+ G_CALLBACK (key_controller_focus_change), spin_button);
gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
}
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index d2396f6f17..51e3233a2a 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -323,8 +323,8 @@ static void gtk_text_size_allocate (GtkWidget *widget,
int baseline);
static void gtk_text_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot);
-static void gtk_text_focus_in (GtkWidget *widget);
-static void gtk_text_focus_out (GtkWidget *widget);
+static void gtk_text_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static gboolean gtk_text_grab_focus (GtkWidget *widget);
static void gtk_text_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
@@ -1781,10 +1781,8 @@ gtk_text_init (GtkText *self)
G_CALLBACK (gtk_text_key_controller_key_pressed), self);
g_signal_connect_swapped (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_schedule_im_reset), self);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_text_focus_in), self);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_text_focus_out), self);
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_text_focus_change), self);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
gtk_widget_add_controller (GTK_WIDGET (self), priv->key_controller);
@@ -3048,55 +3046,53 @@ gtk_text_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
-gtk_text_focus_in (GtkWidget *widget)
+gtk_text_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GdkKeymap *keymap;
- gtk_widget_queue_draw (widget);
-
- keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
-
- if (priv->editable)
+ if (direction == GTK_CROSSING_IN)
{
- gtk_text_schedule_im_reset (self);
- gtk_im_context_focus_in (priv->im_context);
- }
+ gtk_widget_queue_draw (widget);
- g_signal_connect (keymap, "direction-changed",
- G_CALLBACK (keymap_direction_changed), self);
+ keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
- gtk_text_reset_blink_time (self);
- gtk_text_check_cursor_blink (self);
-}
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_in (priv->im_context);
+ }
-static void
-gtk_text_focus_out (GtkWidget *widget)
-{
- GtkText *self = GTK_TEXT (widget);
- GtkTextPrivate *priv = gtk_text_get_instance_private (self);
- GdkKeymap *keymap;
+ g_signal_connect (keymap, "direction-changed",
+ G_CALLBACK (keymap_direction_changed), self);
- gtk_text_selection_bubble_popup_unset (self);
+ gtk_text_reset_blink_time (self);
+ gtk_text_check_cursor_blink (self);
+ }
+ else
+ {
+ gtk_text_selection_bubble_popup_unset (self);
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+ if (priv->text_handle)
+ _gtk_text_handle_set_mode (priv->text_handle,
+ GTK_TEXT_HANDLE_MODE_NONE);
- gtk_widget_queue_draw (widget);
+ gtk_widget_queue_draw (widget);
- keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
+ keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
- if (priv->editable)
- {
- gtk_text_schedule_im_reset (self);
- gtk_im_context_focus_out (priv->im_context);
- }
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_out (priv->im_context);
+ }
- gtk_text_check_cursor_blink (self);
+ gtk_text_check_cursor_blink (self);
- g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
+ g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
+ }
}
static gboolean
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 04aba8b4c8..f55a784741 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -404,8 +404,8 @@ static gboolean gtk_text_view_key_controller_key_pressed (GtkEventControllerKey
static void gtk_text_view_key_controller_im_update (GtkEventControllerKey *controller,
GtkTextView *text_view);
-static void gtk_text_view_focus_in (GtkWidget *widget);
-static void gtk_text_view_focus_out (GtkWidget *widget);
+static void gtk_text_view_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static void gtk_text_view_motion (GtkEventController *controller,
double x,
double y,
@@ -1695,11 +1695,8 @@ gtk_text_view_init (GtkTextView *text_view)
g_signal_connect (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_view_key_controller_im_update),
widget);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_text_view_focus_in),
- widget);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_text_view_focus_out),
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_text_view_focus_change),
widget);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
@@ -5318,72 +5315,65 @@ keymap_direction_changed (GdkKeymap *keymap,
}
static void
-gtk_text_view_focus_in (GtkWidget *widget)
+gtk_text_view_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
- GtkTextView *text_view;
- GtkTextViewPrivate *priv;
-
- text_view = GTK_TEXT_VIEW (widget);
- priv = text_view->priv;
-
- gtk_widget_queue_draw (widget);
-
- DV(g_print (G_STRLOC": focus_in\n"));
-
- gtk_text_view_reset_blink_time (text_view);
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ GtkTextViewPrivate *priv = text_view->priv;
- if (cursor_visible (text_view) && priv->layout)
+ if (direction == GTK_CROSSING_IN)
{
- gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
- gtk_text_view_check_cursor_blink (text_view);
- }
+ gtk_widget_queue_draw (widget);
- g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
- "direction-changed",
- G_CALLBACK (keymap_direction_changed), text_view);
- gtk_text_view_check_keymap_direction (text_view);
+ DV(g_print (G_STRLOC": focus_in\n"));
- if (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_in (priv->im_context);
- }
-}
+ gtk_text_view_reset_blink_time (text_view);
-static void
-gtk_text_view_focus_out (GtkWidget *widget)
-{
- GtkTextView *text_view;
- GtkTextViewPrivate *priv;
+ if (cursor_visible (text_view) && priv->layout)
+ {
+ gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
+ gtk_text_view_check_cursor_blink (text_view);
+ }
- text_view = GTK_TEXT_VIEW (widget);
- priv = text_view->priv;
+ g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
+ "direction-changed",
+ G_CALLBACK (keymap_direction_changed), text_view);
+ gtk_text_view_check_keymap_direction (text_view);
- gtk_text_view_end_selection_drag (text_view);
+ if (priv->editable)
+ {
+ priv->need_im_reset = TRUE;
+ gtk_im_context_focus_in (priv->im_context);
+ }
+ }
+ else
+ {
+ gtk_text_view_end_selection_drag (text_view);
- gtk_widget_queue_draw (widget);
+ gtk_widget_queue_draw (widget);
- DV(g_print (G_STRLOC": focus_out\n"));
+ DV(g_print (G_STRLOC": focus_out\n"));
- if (cursor_visible (text_view) && priv->layout)
- {
- gtk_text_view_check_cursor_blink (text_view);
- gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
- }
+ if (cursor_visible (text_view) && priv->layout)
+ {
+ gtk_text_view_check_cursor_blink (text_view);
+ gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
+ }
- g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
- keymap_direction_changed,
- text_view);
- gtk_text_view_selection_bubble_popup_unset (text_view);
+ g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
+ keymap_direction_changed,
+ text_view);
+ gtk_text_view_selection_bubble_popup_unset (text_view);
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+ if (priv->text_handle)
+ _gtk_text_handle_set_mode (priv->text_handle,
+ GTK_TEXT_HANDLE_MODE_NONE);
- if (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_out (priv->im_context);
+ if (priv->editable)
+ {
+ priv->need_im_reset = TRUE;
+ gtk_im_context_focus_out (priv->im_context);
+ }
}
}
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index cb3f3eb685..6e0574c4d7 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -667,10 +667,9 @@ static void gtk_tree_view_key_controller_key_released (GtkEventControllerKey
guint keycode,
GdkModifierType state,
GtkTreeView *tree_view);
-static void gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkTreeView *tree_view);
+static void gtk_tree_view_key_controller_focus_change (GtkEventController *key,
+ GtkCrossingDirection direction,
+ GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
GtkDirectionType direction);
@@ -1839,8 +1838,8 @@ gtk_tree_view_init (GtkTreeView *tree_view)
G_CALLBACK (gtk_tree_view_key_controller_key_pressed), tree_view);
g_signal_connect (controller, "key-released",
G_CALLBACK (gtk_tree_view_key_controller_key_released), tree_view);
- g_signal_connect (controller, "focus-out",
- G_CALLBACK (gtk_tree_view_key_controller_focus_out), tree_view);
+ g_signal_connect (controller, "focus-change",
+ G_CALLBACK (gtk_tree_view_key_controller_focus_change), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
}
@@ -5546,23 +5545,19 @@ gtk_tree_view_motion_controller_leave (GtkEventControllerMotion *controller,
}
static void
-gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
- GdkCrossingMode mode,
- GdkNotifyType detail,
- GtkTreeView *tree_view)
+gtk_tree_view_key_controller_focus_change (GtkEventController *key,
+ GtkCrossingDirection direction,
+ GtkTreeView *tree_view)
{
- gboolean is_focus, contains_focus;
-
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- g_object_get (key,
- "is-focus", &is_focus,
- "contains-focus", &contains_focus,
- NULL);
+ if (direction == GTK_CROSSING_OUT)
+ {
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- if (tree_view->search_popover && !gtk_event_controller_key_contains_focus (key))
- gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
- gtk_get_current_event_device ());
+ if (tree_view->search_popover &&
+ !gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (key)))
+ gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
+ gtk_get_current_event_device ());
+ }
}
/* Incremental Reflow
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index aa39d9b9ba..790e611036 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -831,11 +831,11 @@ gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout)
static void
focus_in (GtkEventControllerKey *controller,
- GdkCrossingMode mode,
- GdkNotifyType detail,
+ GtkCrossingDirection direction,
GtkTreeViewColumn *column)
{
- _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
+ if (direction == GTK_CROSSING_IN)
+ _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
}
/* Button handling code
@@ -866,7 +866,7 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
gtk_widget_add_controller (priv->button, controller);
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in), tree_column);
+ g_signal_connect (controller, "focus-change", G_CALLBACK (focus_in), tree_column);
gtk_widget_add_controller (priv->button, controller);
priv->frame = gtk_frame_new (NULL);
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 0e937bd10e..57d536d510 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4852,6 +4852,27 @@ gtk_widget_run_controllers (GtkWidget *widget,
return handled;
}
+void
+gtk_widget_handle_crossing (GtkWidget *widget,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+ GList *l;
+
+ g_object_ref (widget);
+
+ for (l = priv->event_controllers; l; l = l->next)
+ {
+ GtkEventController *controller = l->data;
+
+ gtk_event_controller_handle_crossing (controller, crossing, x, y);
+ }
+
+ g_object_unref (widget);
+}
+
static gboolean
translate_event_coordinates (GdkEvent *event,
double *x,
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 87d0eba9c0..bc24a9c728 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -347,6 +347,10 @@ gboolean gtk_widget_run_controllers (GtkWidget
double x,
double y,
GtkPropagationPhase phase);
+void gtk_widget_handle_crossing (GtkWidget *widget,
+ const GtkCrossingData *crossing,
+ double x,
+ double y);
guint gtk_widget_add_surface_transform_changed_callback (GtkWidget
*widget,
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index a8de122391..4302654304 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -394,8 +394,8 @@ static void gtk_window_size_allocate (GtkWidget *widget,
int height,
int baseline);
static gboolean gtk_window_close_request (GtkWindow *window);
-static void gtk_window_focus_in (GtkWidget *widget);
-static void gtk_window_focus_out (GtkWidget *widget);
+static void gtk_window_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction);
static gboolean gtk_window_key_pressed (GtkWidget *widget,
guint keyval,
guint keycode,
@@ -1844,10 +1844,8 @@ gtk_window_init (GtkWindow *window)
priv->key_controller = gtk_event_controller_key_new ();
gtk_event_controller_set_propagation_phase (priv->key_controller, GTK_PHASE_CAPTURE);
- g_signal_connect_swapped (priv->key_controller, "focus-in",
- G_CALLBACK (gtk_window_focus_in), window);
- g_signal_connect_swapped (priv->key_controller, "focus-out",
- G_CALLBACK (gtk_window_focus_out), window);
+ g_signal_connect_swapped (priv->key_controller, "focus-change",
+ G_CALLBACK (gtk_window_focus_change), window);
g_signal_connect_swapped (priv->key_controller, "key-pressed",
G_CALLBACK (gtk_window_key_pressed), window);
g_signal_connect_swapped (priv->key_controller, "key-released",
@@ -6121,33 +6119,33 @@ gtk_window_has_mnemonic_modifier_pressed (GtkWindow *window)
}
static void
-gtk_window_focus_in (GtkWidget *widget)
+gtk_window_focus_change (GtkWidget *widget,
+ GtkCrossingDirection direction)
{
GtkWindow *window = GTK_WINDOW (widget);
- /* It appears spurious focus in events can occur when
- * the window is hidden. So we'll just check to see if
- * the window is visible before actually handling the
- * event
- */
- if (gtk_widget_get_visible (widget))
+ if (direction == GTK_CROSSING_IN)
{
- _gtk_window_set_is_active (window, TRUE);
+ /* It appears spurious focus in events can occur when
+ * the window is hidden. So we'll just check to see if
+ * the window is visible before actually handling the
+ * event
+ */
+ if (gtk_widget_get_visible (widget))
+ {
+ _gtk_window_set_is_active (window, TRUE);
- if (gtk_window_has_mnemonic_modifier_pressed (window))
- _gtk_window_schedule_mnemonics_visible (window);
+ if (gtk_window_has_mnemonic_modifier_pressed (window))
+ _gtk_window_schedule_mnemonics_visible (window);
+ }
}
-}
-
-static void
-gtk_window_focus_out (GtkWidget *widget)
-{
- GtkWindow *window = GTK_WINDOW (widget);
-
- _gtk_window_set_is_active (window, FALSE);
+ else
+ {
+ _gtk_window_set_is_active (window, FALSE);
- /* set the mnemonic-visible property to false */
- gtk_window_set_mnemonics_visible (window, FALSE);
+ /* set the mnemonic-visible property to false */
+ gtk_window_set_mnemonics_visible (window, FALSE);
+ }
}
static void
@@ -6347,6 +6345,61 @@ gtk_window_move_focus (GtkWidget *widget,
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
}
+static void
+synthesize_focus_change_events (GtkWindow *window,
+ GtkWidget *old_focus,
+ GtkWidget *new_focus)
+{
+ GtkCrossingData crossing;
+ GtkWidget *widget, *focus_child;
+ GList *list, *l;
+ GtkStateFlags flags;
+
+ flags = GTK_STATE_FLAG_FOCUSED;
+ if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
+ flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
+
+ crossing.type = GTK_CROSSING_FOCUS;
+ crossing.mode = GDK_CROSSING_NORMAL;
+ crossing.old_target = old_focus;
+ crossing.new_target = new_focus;
+
+ crossing.direction = GTK_CROSSING_OUT;
+
+ widget = old_focus;
+ while (widget)
+ {
+ gtk_widget_handle_crossing (widget, &crossing, 0, 0);
+ gtk_widget_unset_state_flags (widget, flags);
+ gtk_widget_set_focus_child (widget, NULL);
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ list = NULL;
+ widget = new_focus;
+ while (widget)
+ {
+ list = g_list_prepend (list, widget);
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ crossing.direction = GTK_CROSSING_IN;
+
+ for (l = list; l; l = l->next)
+ {
+ widget = l->data;
+ if (l->next)
+ focus_child = l->next->data;
+ else
+ focus_child = NULL;
+ gtk_widget_handle_crossing (widget, &crossing, 0, 0);
+ gtk_widget_set_state_flags (widget, flags, FALSE);
+ gtk_widget_set_focus_child (widget, focus_child);
+ }
+
+ g_list_free (list);
+}
+
/**
* gtk_window_set_focus:
* @window: a #GtkWindow
@@ -6365,9 +6418,6 @@ gtk_window_set_focus (GtkWindow *window,
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GtkWidget *old_focus = NULL;
- GdkSeat *seat;
- GdkDevice *device;
- GdkEvent *event;
g_return_if_fail (GTK_IS_WINDOW (window));
@@ -6381,14 +6431,13 @@ gtk_window_set_focus (GtkWindow *window,
old_focus = g_object_ref (priv->focus_widget);
g_set_object (&priv->focus_widget, NULL);
- seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (window)));
- device = gdk_seat_get_keyboard (seat);
+ if (old_focus)
+ gtk_widget_set_has_focus (old_focus, FALSE);
- event = gdk_event_focus_new (priv->surface, device, device, TRUE);
+ synthesize_focus_change_events (window, old_focus, focus);
- gtk_synthesize_crossing_events (GTK_ROOT (window), old_focus, focus, event, GDK_CROSSING_NORMAL);
-
- gdk_event_unref (event);
+ if (focus)
+ gtk_widget_set_has_focus (focus, TRUE);
g_set_object (&priv->focus_widget, focus);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]