[gtk/readonly-events-1] Split off GtkEventControllerFocus
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/readonly-events-1] Split off GtkEventControllerFocus
- Date: Thu, 20 Feb 2020 02:25:31 +0000 (UTC)
commit b9a0a1d65a09dd05a76920e14c54a8904d7cf83c
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Feb 19 20:51:03 2020 -0500
Split off GtkEventControllerFocus
Split the focus tracking into a separate
GtkEventControllerFocus, and change the API one more time.
We are back to having ::focus-in and ::focus-out signals.
Update all users.
gtk/gtk.h | 1 +
gtk/gtkcalendar.c | 18 ++-
gtk/gtkentrycompletion.c | 12 +-
gtk/gtkentryprivate.h | 1 +
gtk/gtkeventcontrollerfocus.c | 361 ++++++++++++++++++++++++++++++++++++++++++
gtk/gtkeventcontrollerfocus.h | 66 ++++++++
gtk/gtkeventcontrollerkey.c | 244 ----------------------------
gtk/gtkeventcontrollerkey.h | 14 --
gtk/gtkfilechooserentry.c | 13 +-
gtk/gtkmodelbutton.c | 21 ++-
gtk/gtkpopovermenu.c | 14 +-
gtk/gtkspinbutton.c | 15 +-
gtk/gtktext.c | 77 +++++----
gtk/gtktextview.c | 100 ++++++------
gtk/gtktreeview.c | 29 ++--
gtk/gtktreeviewcolumn.c | 9 +-
gtk/gtkwindow.c | 54 ++++---
gtk/meson.build | 1 +
testsuite/gtk/focus.c | 73 +++++----
19 files changed, 662 insertions(+), 461 deletions(-)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 07236ce5f1..46c7aabacc 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -101,6 +101,7 @@
#include <gtk/gtkentrycompletion.h>
#include <gtk/gtkenums.h>
#include <gtk/gtkeventcontroller.h>
+#include <gtk/gtkeventcontrollerfocus.h>
#include <gtk/gtkeventcontrollerkey.h>
#include <gtk/gtkeventcontrollerlegacy.h>
#include <gtk/gtkeventcontrollermotion.h>
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 95e5b19aaa..09eca8b12c 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -109,6 +109,7 @@
#include "gtkgesturedrag.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerkey.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkdragsource.h"
#include "gtknative.h"
#include "gtkicontheme.h"
@@ -280,8 +281,7 @@ static gboolean gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *
guint keycode,
GdkModifierType state,
GtkWidget *widget);
-static void gtk_calendar_key_controller_focus (GtkEventController *controller,
- GtkCrossingDirection direction,
+static void gtk_calendar_focus_controller_focus (GtkEventController *controller,
GtkWidget *widget);
static void gtk_calendar_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
@@ -593,8 +593,13 @@ 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-change",
- G_CALLBACK (gtk_calendar_key_controller_focus),
+ gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "enter",
+ G_CALLBACK (gtk_calendar_focus_controller_focus),
+ calendar);
+ g_signal_connect (controller, "leave",
+ G_CALLBACK (gtk_calendar_focus_controller_focus),
calendar);
gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
@@ -1398,9 +1403,8 @@ gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
-gtk_calendar_key_controller_focus (GtkEventController *controller,
- GtkCrossingDirection direction,
- GtkWidget *widget)
+gtk_calendar_focus_controller_focus (GtkEventController *controller,
+ 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 4167b7e104..a3c642edc8 100644
--- a/gtk/gtkentrycompletion.c
+++ b/gtk/gtkentrycompletion.c
@@ -83,6 +83,7 @@
#include "gtkentry.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkgestureclick.h"
@@ -2308,11 +2309,9 @@ accept_completion_callback (GtkEntryCompletion *completion)
}
static void
-text_focus_change (GtkEntryCompletion *completion,
- GtkCrossingDirection direction)
+text_focus_out (GtkEntryCompletion *completion)
{
- if (direction == GTK_CROSSING_OUT &&
- !gtk_widget_get_mapped (completion->priv->popup_window))
+ if (!gtk_widget_get_mapped (completion->priv->popup_window))
accept_completion_callback (completion);
}
@@ -2349,7 +2348,9 @@ 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-change", G_CALLBACK (text_focus_change), completion);
+ gtk_widget_add_controller (GTK_WIDGET (text), controller);
+ controller = priv->entry_focus_controller = gtk_event_controller_focus_new ();
+ g_signal_connect_swapped (controller, "leave", G_CALLBACK (text_focus_out), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
completion->priv->changed_id =
@@ -2397,6 +2398,7 @@ disconnect_completion_signals (GtkEntryCompletion *completion)
GtkText *text = gtk_entry_get_text_widget (GTK_ENTRY (completion->priv->entry));
gtk_widget_remove_controller (GTK_WIDGET (text), completion->priv->entry_key_controller);
+ gtk_widget_remove_controller (GTK_WIDGET (text), completion->priv->entry_focus_controller);
if (completion->priv->changed_id > 0 &&
g_signal_handler_is_connected (text, completion->priv->changed_id))
diff --git a/gtk/gtkentryprivate.h b/gtk/gtkentryprivate.h
index 2f7d8dc695..de765d9b49 100644
--- a/gtk/gtkentryprivate.h
+++ b/gtk/gtkentryprivate.h
@@ -78,6 +78,7 @@ struct _GtkEntryCompletionPrivate
gchar *case_normalized_key;
GtkEventController *entry_key_controller;
+ GtkEventController *entry_focus_controller;
/* only used by GtkEntry when attached: */
GtkWidget *popup_window;
diff --git a/gtk/gtkeventcontrollerfocus.c b/gtk/gtkeventcontrollerfocus.c
new file mode 100644
index 0000000000..24d2a4eca0
--- /dev/null
+++ b/gtk/gtkeventcontrollerfocus.c
@@ -0,0 +1,361 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2020, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Matthias Clasen <mclasen redhat com>
+ */
+
+/**
+ * SECTION:gtkeventcontrollerfocus
+ * @Short_description: Event controller for focus
+ * @Title: GtkEventControllerFocus
+ * @See_also: #GtkEventController
+ *
+ * #GtkEventControllerFocus is an event controller meant for situations
+ * where you need to know where the focusboard focus is.
+ **/
+
+#include "config.h"
+
+#include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
+#include "gtkeventcontrollerprivate.h"
+#include "gtkeventcontrollerfocus.h"
+#include "gtkbindings.h"
+#include "gtkenums.h"
+#include "gtkmain.h"
+#include "gtktypebuiltins.h"
+
+#include <gdk/gdk.h>
+
+struct _GtkEventControllerFocus
+{
+ GtkEventController parent_instance;
+
+ const GtkCrossingData *current_crossing;
+
+ guint is_focus : 1;
+ guint contains_focus : 1;
+};
+
+struct _GtkEventControllerFocusClass
+{
+ GtkEventControllerClass parent_class;
+};
+
+enum {
+ ENTER,
+ LEAVE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+enum {
+ PROP_IS_FOCUS = 1,
+ PROP_CONTAINS_FOCUS,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE (GtkEventControllerFocus, gtk_event_controller_focus,
+ GTK_TYPE_EVENT_CONTROLLER)
+
+static void
+gtk_event_controller_focus_finalize (GObject *object)
+{
+ //GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (object);
+
+ G_OBJECT_CLASS (gtk_event_controller_focus_parent_class)->finalize (object);
+}
+
+static void
+update_focus (GtkEventController *controller,
+ const GtkCrossingData *crossing)
+{
+ GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (controller);
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ gboolean is_focus = FALSE;
+ gboolean contains_focus = FALSE;
+ gboolean enter = FALSE;
+ gboolean leave = FALSE;
+
+ if (crossing->direction == GTK_CROSSING_IN)
+ {
+ if (crossing->new_target == widget)
+ is_focus = TRUE;
+ if (crossing->new_target != NULL)
+ contains_focus = TRUE;
+ }
+
+ if (focus->contains_focus != contains_focus)
+ {
+ if (contains_focus)
+ enter = TRUE;
+ else
+ leave = TRUE;
+ }
+
+ if (enter)
+ g_signal_emit (controller, signals[ENTER], 0);
+
+ g_object_freeze_notify (G_OBJECT (focus));
+ if (focus->is_focus != is_focus)
+ {
+ focus->is_focus = is_focus;
+ g_object_notify (G_OBJECT (focus), "is-focus");
+ }
+
+ if (focus->contains_focus != contains_focus)
+ {
+ focus->contains_focus = contains_focus;
+ g_object_notify (G_OBJECT (focus), "contains-focus");
+ }
+ g_object_thaw_notify (G_OBJECT (focus));
+
+ if (leave)
+ g_signal_emit (controller, signals[LEAVE], 0);
+}
+
+static void
+gtk_event_controller_focus_handle_crossing (GtkEventController *controller,
+ const GtkCrossingData *crossing,
+ double x,
+ double y)
+{
+ GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (controller);
+
+ if (crossing->type != GTK_CROSSING_FOCUS)
+ return;
+
+ focus->current_crossing = crossing;
+
+ update_focus (controller, crossing);
+
+ focus->current_crossing = NULL;
+}
+
+static void
+gtk_event_controller_focus_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkEventControllerFocus *controller = GTK_EVENT_CONTROLLER_FOCUS (object);
+
+ switch (prop_id)
+ {
+ case PROP_IS_FOCUS:
+ g_value_set_boolean (value, controller->is_focus);
+ break;
+
+ case PROP_CONTAINS_FOCUS:
+ g_value_set_boolean (value, controller->contains_focus);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_event_controller_focus_class_init (GtkEventControllerFocusClass *klass)
+{
+ GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_event_controller_focus_finalize;
+ object_class->get_property = gtk_event_controller_focus_get_property;
+ controller_class->handle_crossing = gtk_event_controller_focus_handle_crossing;
+
+ /**
+ * GtkEventControllerFocus:is-focus:
+ *
+ * Whether focus is in the controllers widget itself,
+ * opposed to in a descendent widget. See also
+ * #GtkEventControllerFocus:contains-focus.
+ *
+ * When handling focus events, this property is updated
+ * before #GtkEventControllerFocus::focus-in or
+ * #GtkEventControllerFocus::focus-out are emitted.
+ */
+ props[PROP_IS_FOCUS] =
+ g_param_spec_boolean ("is-focus",
+ P_("Is Focus"),
+ P_("Whether the focus is in the controllers widget"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ /**
+ * GtkEventControllerFocus:contains-focus:
+ *
+ * Whether focus is contain in the controllers widget. See
+ * See #GtkEventControllerFocus:is-focus for whether the focus is in the widget itself
+ * or inside a descendent.
+ *
+ * When handling focus events, this property is updated
+ * before #GtkEventControllerFocus::focus-in or
+ * #GtkEventControllerFocus::focus-out are emitted.
+ */
+ props[PROP_CONTAINS_FOCUS] =
+ g_param_spec_boolean ("contains-focus",
+ P_("Contains Focus"),
+ P_("Whether the focus is in a descendant of the controllers widget"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
+
+ /**
+ * GtkEventControllerFocus::enter:
+ * @controller: the object which received the signal
+ *
+ * This signal is emitted whenever the focus enters into the
+ * widget or one of its descendents.
+ */
+ signals[ENTER] =
+ g_signal_new (I_("enter"),
+ GTK_TYPE_EVENT_CONTROLLER_FOCUS,
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * GtkEventControllerFocus::leave:
+ * @controller: the object which received the signal
+ *
+ * This signal is emitted whenever the focus leaves from
+ * the widget or one of its descendents.
+ */
+ signals[LEAVE] =
+ g_signal_new (I_("leave"),
+ GTK_TYPE_EVENT_CONTROLLER_FOCUS,
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gtk_event_controller_focus_init (GtkEventControllerFocus *controller)
+{
+}
+
+/**
+ * gtk_event_controller_focus_new:
+ *
+ * Creates a new event controller that will handle focus events.
+ *
+ * Returns: a new #GtkEventControllerFocus
+ **/
+GtkEventController *
+gtk_event_controller_focus_new (void)
+{
+ return g_object_new (GTK_TYPE_EVENT_CONTROLLER_FOCUS, NULL);
+}
+
+/**
+ * gtk_event_controller_focus_get_focus_origin:
+ * @controller: a #GtkEventControllerFocus
+ *
+ * Returns the widget that was holding focus before.
+ *
+ * This function can only be used in handlers for the
+ * #GtkEventControllerFocus::focus-in and #GtkEventControllerFocus::focus-out signals.
+ *
+ * Returns: (transfer none): the previous focus
+ */
+GtkWidget *
+gtk_event_controller_focus_get_focus_origin (GtkEventControllerFocus *controller)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+ return controller->current_crossing->old_target;
+}
+
+/**
+ * gtk_event_controller_focus_get_focus_target:
+ * @controller: a #GtkEventControllerFocus
+ *
+ * Returns the widget that will be holding focus afterwards.
+ *
+ * This function can only be used in handlers for the
+ * #GtkEventControllerFocus::focus-in and #GtkEventControllerFocus::focus-out signals.
+ *
+ * Returns: (transfer none): the next focus
+ */
+GtkWidget *
+gtk_event_controller_focus_get_focus_target (GtkEventControllerFocus *controller)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+ return controller->current_crossing->new_target;
+}
+
+GtkWidget *
+gtk_event_controller_focus_get_old_focus_child (GtkEventControllerFocus *controller)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+ return controller->current_crossing->old_descendent;
+}
+
+GtkWidget *
+gtk_event_controller_focus_get_new_focus_child (GtkEventControllerFocus *controller)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
+ g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+ return controller->current_crossing->new_descendent;
+}
+
+/**
+ * gtk_event_controller_focus_contains_focus:
+ * @self: a #GtkEventControllerFocus
+ *
+ * Returns the value of the GtkEventControllerFocus:contains-focus property.
+ *
+ * Returns: %TRUE if focus is within @self or one of its children
+ */
+gboolean
+gtk_event_controller_focus_contains_focus (GtkEventControllerFocus *self)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (self), FALSE);
+
+ return self->contains_focus;
+}
+
+/**
+ * gtk_event_controller_focus_is_focus:
+ * @self: a #GtkEventControllerFocus
+ *
+ * Returns the value of the GtkEventControllerFocus:is-focus property.
+ *
+ * Returns: %TRUE if focus is within @self but not one of its children
+ */
+gboolean
+gtk_event_controller_focus_is_focus (GtkEventControllerFocus *self)
+{
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (self), FALSE);
+
+ return self->is_focus;
+}
diff --git a/gtk/gtkeventcontrollerfocus.h b/gtk/gtkeventcontrollerfocus.h
new file mode 100644
index 0000000000..3a4ae1b7fe
--- /dev/null
+++ b/gtk/gtkeventcontrollerfocus.h
@@ -0,0 +1,66 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2020, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_EVENT_CONTROLLER_FOCUS_H__
+#define __GTK_EVENT_CONTROLLER_FOCUS_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+#include <gtk/gtkeventcontroller.h>
+#include <gtk/gtkimcontext.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EVENT_CONTROLLER_FOCUS (gtk_event_controller_focus_get_type ())
+#define GTK_EVENT_CONTROLLER_FOCUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocus))
+#define GTK_EVENT_CONTROLLER_FOCUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocusClass))
+#define GTK_IS_EVENT_CONTROLLER_FOCUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GTK_TYPE_EVENT_CONTROLLER_FOCUS))
+#define GTK_IS_EVENT_CONTROLLER_FOCUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GTK_TYPE_EVENT_CONTROLLER_FOCUS))
+#define GTK_EVENT_CONTROLLER_FOCUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocusClass))
+
+typedef struct _GtkEventControllerFocus GtkEventControllerFocus;
+typedef struct _GtkEventControllerFocusClass GtkEventControllerFocusClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_event_controller_focus_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkEventController *gtk_event_controller_focus_new (void);
+
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_focus_get_focus_origin (GtkEventControllerFocus *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_focus_get_focus_target (GtkEventControllerFocus *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_focus_get_old_focus_child (GtkEventControllerFocus *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_focus_get_new_focus_child (GtkEventControllerFocus *controller);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_event_controller_focus_contains_focus (GtkEventControllerFocus *self);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_event_controller_focus_is_focus (GtkEventControllerFocus *self);
+
+
+G_END_DECLS
+
+#endif /* __GTK_EVENT_CONTROLLER_FOCUS_H__ */
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index 14a79e7b0c..79103f407c 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -51,7 +51,6 @@ struct _GtkEventControllerKey
GdkModifierType state;
GdkEvent *current_event;
- const GtkCrossingData *current_crossing;
guint is_focus : 1;
guint contains_focus : 1;
@@ -67,20 +66,11 @@ enum {
KEY_RELEASED,
MODIFIERS,
IM_UPDATE,
- FOCUS_CHANGE,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
-enum {
- PROP_IS_FOCUS = 1,
- PROP_CONTAINS_FOCUS,
- NUM_PROPERTIES
-};
-
-static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
-
G_DEFINE_TYPE (GtkEventControllerKey, gtk_event_controller_key,
GTK_TYPE_EVENT_CONTROLLER)
@@ -155,87 +145,6 @@ 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,
- GValue *value,
- GParamSpec *pspec)
-{
- GtkEventControllerKey *controller = GTK_EVENT_CONTROLLER_KEY (object);
-
- switch (prop_id)
- {
- case PROP_IS_FOCUS:
- g_value_set_boolean (value, controller->is_focus);
- break;
-
- case PROP_CONTAINS_FOCUS:
- g_value_set_boolean (value, controller->contains_focus);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
static void
gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
{
@@ -243,47 +152,7 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (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:
- *
- * Whether focus is in the controllers widget itself,
- * opposed to in a descendent widget. See also
- * #GtkEventControllerKey:contains-focus.
- *
- * When handling focus events, this property is updated
- * before #GtkEventControllerKey::focus-in or
- * #GtkEventControllerKey::focus-out are emitted.
- */
- props[PROP_IS_FOCUS] =
- g_param_spec_boolean ("is-focus",
- P_("Is Focus"),
- P_("Whether the focus is in the controllers widget"),
- FALSE,
- G_PARAM_READABLE);
-
- /**
- * GtkEventControllerKey:contains-focus:
- *
- * Whether focus is contain in the controllers widget. See
- * See #GtkEventControllerKey:is-focus for whether the focus is in the widget itself
- * or inside a descendent.
- *
- * When handling focus events, this property is updated
- * before #GtkEventControllerKey::focus-in or
- * #GtkEventControllerKey::focus-out are emitted.
- */
- props[PROP_CONTAINS_FOCUS] =
- g_param_spec_boolean ("contains-focus",
- P_("Contains Focus"),
- P_("Whether the focus is in a descendant of the controllers widget"),
- FALSE,
- G_PARAM_READABLE);
-
- g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
/**
* GtkEventControllerKey::key-pressed:
@@ -365,29 +234,6 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
0, NULL, NULL,
NULL,
G_TYPE_NONE, 0);
-
- /**
- * GtkEventControllerKey::focus-change:
- * @controller: the object which received the signal
- * @direction: the direction of this crossing event
- *
- * 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.
- *
- * 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_CHANGE] =
- g_signal_new (I_("focus-change"),
- GTK_TYPE_EVENT_CONTROLLER_KEY,
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- GTK_TYPE_CROSSING_DIRECTION);
}
static void
@@ -507,93 +353,3 @@ gtk_event_controller_key_get_group (GtkEventControllerKey *controller)
return gdk_key_event_get_group (controller->current_event);
}
-
-/**
- * gtk_event_controller_key_get_focus_origin:
- * @controller: a #GtkEventControllerKey
- *
- * Returns the widget that was holding focus before.
- *
- * This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-changed signal.
- *
- * Returns: (transfer none): the previous focus
- */
-GtkWidget *
-gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_crossing != NULL, NULL);
-
- return controller->current_crossing->old_target;
-}
-
-/**
- * gtk_event_controller_key_get_focus_target:
- * @controller: a #GtkEventControllerKey
- *
- * Returns the widget that will be holding focus afterwards.
- *
- * This function can only be used in handlers for the
- * #GtkEventControllerKey::focus-changed signal.
- *
- * Returns: (transfer none): the next focus
- */
-GtkWidget *
-gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_crossing != NULL, NULL);
-
- return controller->current_crossing->new_target;
-}
-
-GtkWidget *
-gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey *controller)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_crossing != NULL, NULL);
-
- return controller->current_crossing->old_descendent;
-}
-
-GtkWidget *
-gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey *controller)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
- g_return_val_if_fail (controller->current_crossing != NULL, NULL);
-
- return controller->current_crossing->new_descendent;
-}
-
-/**
- * gtk_event_controller_key_contains_focus:
- * @self: a #GtkEventControllerKey
- *
- * Returns the value of the GtkEventControllerKey:contains-focus property.
- *
- * Returns: %TRUE if focus is within @self or one of its children
- */
-gboolean
-gtk_event_controller_key_contains_focus (GtkEventControllerKey *self)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (self), FALSE);
-
- return self->contains_focus;
-}
-
-/**
- * gtk_event_controller_key_is_focus:
- * @self: a #GtkEventControllerKey
- *
- * Returns the value of the GtkEventControllerKey:is-focus property.
- *
- * Returns: %TRUE if focus is within @self but not one of its children
- */
-gboolean
-gtk_event_controller_key_is_focus (GtkEventControllerKey *self)
-{
- g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (self), FALSE);
-
- return self->is_focus;
-}
diff --git a/gtk/gtkeventcontrollerkey.h b/gtk/gtkeventcontrollerkey.h
index 4aa22777d6..b24df105d0 100644
--- a/gtk/gtkeventcontrollerkey.h
+++ b/gtk/gtkeventcontrollerkey.h
@@ -58,20 +58,6 @@ gboolean gtk_event_controller_key_forward (GtkEventControllerK
GDK_AVAILABLE_IN_ALL
guint gtk_event_controller_key_get_group (GtkEventControllerKey *controller);
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller);
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller);
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey *controller);
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey *controller);
-
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_event_controller_key_contains_focus (GtkEventControllerKey *self);
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_event_controller_key_is_focus (GtkEventControllerKey *self);
-
G_END_DECLS
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 9123bddb91..09146f4963 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -33,6 +33,7 @@
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkfilefilterprivate.h"
+#include "gtkeventcontrollerfocus.h"
typedef struct _GtkFileChooserEntryClass GtkFileChooserEntryClass;
@@ -259,12 +260,10 @@ match_func (GtkEntryCompletion *compl,
}
static void
-chooser_entry_focus_change (GtkEventController *controller,
- GtkCrossingDirection direction,
- GtkFileChooserEntry *chooser_entry)
+chooser_entry_focus_out (GtkEventController *controller,
+ GtkFileChooserEntry *chooser_entry)
{
- if (direction == GTK_CROSSING_OUT)
- set_complete_on_load (chooser_entry, FALSE);
+ set_complete_on_load (chooser_entry, FALSE);
}
static void
@@ -311,8 +310,10 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
"key-pressed",
G_CALLBACK (gtk_file_chooser_entry_tab_handler),
chooser_entry);
+ gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);
+ controller = gtk_event_controller_focus_new ();
g_signal_connect (controller,
- "focus-change", G_CALLBACK (chooser_entry_focus_change),
+ "leave", G_CALLBACK (chooser_entry_focus_out),
chooser_entry);
gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index d60b7b16c5..803006f95c 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -44,6 +44,7 @@
#include "gtkactionable.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerkey.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtknative.h"
/**
@@ -1349,21 +1350,17 @@ motion_cb (GtkEventController *controller,
}
static void
-focus_change_cb (GtkEventController *controller,
- GtkCrossingDirection direction,
- gpointer data)
+focus_in_cb (GtkEventController *controller,
+ gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
- if (direction == GTK_CROSSING_IN)
- {
- target = gtk_event_controller_get_widget (controller);
- popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
+ 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
@@ -1390,8 +1387,8 @@ gtk_model_button_init (GtkModelButton *self)
g_signal_connect (controller, "motion", G_CALLBACK (motion_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
- controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change_cb), NULL);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "enter", G_CALLBACK (focus_in_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
gesture = gtk_gesture_click_new ();
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index c8f4afe6a4..50eccf17dc 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -28,7 +28,7 @@
#include "gtkmenutrackerprivate.h"
#include "gtkpopoverprivate.h"
#include "gtkwidgetprivate.h"
-#include "gtkeventcontrollerkey.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkmain.h"
#include "gtktypebuiltins.h"
@@ -168,14 +168,12 @@ visible_submenu_changed (GObject *object,
}
static void
-focus_change (GtkEventController *controller,
- GtkCrossingDirection direction,
- GtkPopoverMenu *menu)
+focus_out (GtkEventController *controller,
+ GtkPopoverMenu *menu)
{
GtkWidget *new_focus = gtk_root_get_focus (gtk_widget_get_root (GTK_WIDGET (menu)));
- if (direction == GTK_CROSSING_OUT &&
- !gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (controller)) &&
+ if (!gtk_event_controller_focus_contains_focus (GTK_EVENT_CONTROLLER_FOCUS (controller)) &&
new_focus != NULL)
{
if (menu->parent_menu &&
@@ -220,8 +218,8 @@ 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-change", G_CALLBACK (focus_change), popover);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "leave", G_CALLBACK (focus_out), 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 ec1d3a0da0..d0147ab297 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -39,6 +39,7 @@
#include "gtkimage.h"
#include "gtktext.h"
#include "gtkeventcontrollerkey.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkgestureclick.h"
@@ -920,14 +921,12 @@ key_controller_key_released (GtkEventControllerKey *key,
}
static void
-key_controller_focus_change (GtkEventController *controller,
- GtkCrossingDirection direction,
- GtkSpinButton *spin_button)
+key_controller_focus_out (GtkEventController *controller,
+ GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin_button);
- if (direction == GTK_CROSSING_OUT &&
- gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
+ if (gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
gtk_spin_button_update (spin_button);
}
@@ -1015,8 +1014,10 @@ 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-change",
- G_CALLBACK (key_controller_focus_change), spin_button);
+ gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "leave",
+ G_CALLBACK (key_controller_focus_out), spin_button);
gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
}
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 00c07d6d3f..17063ee477 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -34,6 +34,7 @@
#include "gtkemojichooser.h"
#include "gtkemojicompletion.h"
#include "gtkentrybuffer.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
#include "gtkgesturedrag.h"
@@ -323,8 +324,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_change (GtkWidget *widget,
- GtkCrossingDirection direction);
+static void gtk_text_focus_in (GtkWidget *widget);
+static void gtk_text_focus_out (GtkWidget *widget);
static gboolean gtk_text_grab_focus (GtkWidget *widget);
static void gtk_text_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
@@ -1783,11 +1784,15 @@ 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-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);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect_swapped (controller, "enter",
+ G_CALLBACK (gtk_text_focus_in), self);
+ g_signal_connect_swapped (controller, "leave",
+ G_CALLBACK (gtk_text_focus_out), self);
+ gtk_widget_add_controller (GTK_WIDGET (self), controller);
widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
for (i = 0; i < 2; i++)
@@ -3052,53 +3057,55 @@ gtk_text_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
-gtk_text_focus_change (GtkWidget *widget,
- GtkCrossingDirection direction)
+gtk_text_focus_in (GtkWidget *widget)
{
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GdkKeymap *keymap;
- if (direction == GTK_CROSSING_IN)
- {
- 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_in (priv->im_context);
- }
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_in (priv->im_context);
+ }
- g_signal_connect (keymap, "direction-changed",
- G_CALLBACK (keymap_direction_changed), self);
+ g_signal_connect (keymap, "direction-changed",
+ G_CALLBACK (keymap_direction_changed), self);
- gtk_text_reset_blink_time (self);
- gtk_text_check_cursor_blink (self);
- }
- else
- {
- gtk_text_selection_bubble_popup_unset (self);
+ gtk_text_reset_blink_time (self);
+ gtk_text_check_cursor_blink (self);
+}
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+static void
+gtk_text_focus_out (GtkWidget *widget)
+{
+ GtkText *self = GTK_TEXT (widget);
+ GtkTextPrivate *priv = gtk_text_get_instance_private (self);
+ GdkKeymap *keymap;
- gtk_widget_queue_draw (widget);
+ gtk_text_selection_bubble_popup_unset (self);
- keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
+ if (priv->text_handle)
+ _gtk_text_handle_set_mode (priv->text_handle,
+ GTK_TEXT_HANDLE_MODE_NONE);
- if (priv->editable)
- {
- gtk_text_schedule_im_reset (self);
- gtk_im_context_focus_out (priv->im_context);
- }
+ gtk_widget_queue_draw (widget);
- gtk_text_check_cursor_blink (self);
+ keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
- g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
+ if (priv->editable)
+ {
+ gtk_text_schedule_im_reset (self);
+ gtk_im_context_focus_out (priv->im_context);
}
+
+ gtk_text_check_cursor_blink (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 c161237831..1051264b00 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_change (GtkWidget *widget,
- GtkCrossingDirection direction);
+static void gtk_text_view_focus_in (GtkWidget *widget);
+static void gtk_text_view_focus_out (GtkWidget *widget);
static void gtk_text_view_motion (GtkEventController *controller,
double x,
double y,
@@ -1698,12 +1698,15 @@ 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-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);
gtk_widget_add_controller (widget, priv->key_controller);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect_swapped (controller, "enter",
+ G_CALLBACK (gtk_text_view_focus_in), widget);
+ g_signal_connect_swapped (controller, "leave",
+ G_CALLBACK (gtk_text_view_focus_out), widget);
+ gtk_widget_add_controller (widget, controller);
priv->selection_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->selection_node, g_quark_from_static_string ("selection"));
@@ -5310,65 +5313,66 @@ keymap_direction_changed (GdkKeymap *keymap,
}
static void
-gtk_text_view_focus_change (GtkWidget *widget,
- GtkCrossingDirection direction)
+gtk_text_view_focus_in (GtkWidget *widget)
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
GtkTextViewPrivate *priv = text_view->priv;
- if (direction == GTK_CROSSING_IN)
- {
- gtk_widget_queue_draw (widget);
+ gtk_widget_queue_draw (widget);
- DV(g_print (G_STRLOC": focus_in\n"));
+ DV(g_print (G_STRLOC": focus_in\n"));
- gtk_text_view_reset_blink_time (text_view);
+ gtk_text_view_reset_blink_time (text_view);
- if (cursor_visible (text_view) && priv->layout)
- {
- gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
- gtk_text_view_check_cursor_blink (text_view);
- }
+ if (cursor_visible (text_view) && priv->layout)
+ {
+ gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
+ gtk_text_view_check_cursor_blink (text_view);
+ }
- 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);
+ 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);
- if (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_in (priv->im_context);
- }
+ 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);
+static void
+gtk_text_view_focus_out (GtkWidget *widget)
+{
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ GtkTextViewPrivate *priv = text_view->priv;
- DV(g_print (G_STRLOC": focus_out\n"));
+ gtk_text_view_end_selection_drag (text_view);
- if (cursor_visible (text_view) && priv->layout)
- {
- gtk_text_view_check_cursor_blink (text_view);
- gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
- }
+ gtk_widget_queue_draw (widget);
- 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);
+ DV(g_print (G_STRLOC": focus_out\n"));
- if (priv->text_handle)
- _gtk_text_handle_set_mode (priv->text_handle,
- GTK_TEXT_HANDLE_MODE_NONE);
+ 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 (priv->editable)
- {
- priv->need_im_reset = TRUE;
- gtk_im_context_focus_out (priv->im_context);
- }
+ 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->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 7a0585c645..eccacdc91b 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -37,6 +37,7 @@
#include "gtkentryprivate.h"
#include "gtksearchentryprivate.h"
#include "gtkeventcontrollerkey.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkframe.h"
@@ -667,8 +668,7 @@ 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_change (GtkEventController *key,
- GtkCrossingDirection direction,
+static void gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
@@ -1832,8 +1832,11 @@ 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-change",
- G_CALLBACK (gtk_tree_view_key_controller_focus_change), tree_view);
+ gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
+
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "leave",
+ G_CALLBACK (gtk_tree_view_focus_controller_focus_out), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
}
@@ -5537,19 +5540,15 @@ gtk_tree_view_motion_controller_pointer (GtkEventControllerMotion *controller,
}
static void
-gtk_tree_view_key_controller_focus_change (GtkEventController *key,
- GtkCrossingDirection direction,
- GtkTreeView *tree_view)
+gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
+ GtkTreeView *tree_view)
{
- if (direction == GTK_CROSSING_OUT)
- {
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- 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 ());
- }
+ if (tree_view->search_popover &&
+ !gtk_event_controller_focus_contains_focus (GTK_EVENT_CONTROLLER_FOCUS (focus)))
+ 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 790e611036..a70c893a49 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -35,6 +35,7 @@
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkgesturedrag.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "a11y/gtktreeviewaccessibleprivate.h"
@@ -831,11 +832,9 @@ gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout)
static void
focus_in (GtkEventControllerKey *controller,
- GtkCrossingDirection direction,
GtkTreeViewColumn *column)
{
- if (direction == GTK_CROSSING_IN)
- _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
+ _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
}
/* Button handling code
@@ -865,8 +864,8 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
gtk_widget_add_controller (priv->button, controller);
- controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-change", G_CALLBACK (focus_in), tree_column);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "enter", G_CALLBACK (focus_in), tree_column);
gtk_widget_add_controller (priv->button, controller);
priv->frame = gtk_frame_new (NULL);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 01a2e9dfc3..6ae7b55ac4 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -41,6 +41,7 @@
#include "gtkcssshadowvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkdragdest.h"
+#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
#include "gtkgesturedrag.h"
@@ -394,8 +395,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_change (GtkWidget *widget,
- GtkCrossingDirection direction);
+static void gtk_window_focus_in (GtkWidget *widget);
+static void gtk_window_focus_out (GtkWidget *widget);
static gboolean gtk_window_key_pressed (GtkWidget *widget,
guint keyval,
guint keycode,
@@ -1772,6 +1773,7 @@ gtk_window_init (GtkWindow *window)
GtkCssNode *widget_node;
GdkSeat *seat;
GtkEventController *motion_controller;
+ GtkEventController *controller;
#ifdef GDK_WINDOWING_X11
GdkContentFormats *targets;
GtkDropTarget *dest;
@@ -1846,13 +1848,17 @@ 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-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",
G_CALLBACK (gtk_window_key_released), window);
gtk_widget_add_controller (widget, priv->key_controller);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect_swapped (controller, "enter",
+ G_CALLBACK (gtk_window_focus_in), window);
+ g_signal_connect_swapped (controller, "leave",
+ G_CALLBACK (gtk_window_focus_out), window);
+ gtk_widget_add_controller (widget, controller);
/* Shared constraint solver */
priv->constraint_solver = gtk_constraint_solver_new ();
@@ -6123,33 +6129,33 @@ gtk_window_has_mnemonic_modifier_pressed (GtkWindow *window)
}
static void
-gtk_window_focus_change (GtkWidget *widget,
- GtkCrossingDirection direction)
+gtk_window_focus_in (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
- if (direction == GTK_CROSSING_IN)
+ /* 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))
{
- /* 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);
+ _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);
}
- else
- {
- _gtk_window_set_is_active (window, FALSE);
+}
- /* set the mnemonic-visible property to false */
- gtk_window_set_mnemonics_visible (window, FALSE);
- }
+static void
+gtk_window_focus_out (GtkWidget *widget)
+{
+ GtkWindow *window = GTK_WINDOW (widget);
+
+ _gtk_window_set_is_active (window, FALSE);
+
+ /* set the mnemonic-visible property to false */
+ gtk_window_set_mnemonics_visible (window, FALSE);
}
static void
diff --git a/gtk/meson.build b/gtk/meson.build
index b57a7e33ad..a09b672130 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -218,6 +218,7 @@ gtk_public_sources = files([
'gtkentrybuffer.c',
'gtkentrycompletion.c',
'gtkeventcontroller.c',
+ 'gtkeventcontrollerfocus.c',
'gtkeventcontrollerkey.c',
'gtkeventcontrollerlegacy.c',
'gtkeventcontrollermotion.c',
diff --git a/testsuite/gtk/focus.c b/testsuite/gtk/focus.c
index ac6d43fd7b..854236d57d 100644
--- a/testsuite/gtk/focus.c
+++ b/testsuite/gtk/focus.c
@@ -14,17 +14,27 @@ widget_name (GtkWidget *widget)
}
static void
-focus_change (GtkEventControllerKey *key,
- GtkCrossingDirection direction,
- GString *s)
+focus_in (GtkEventControllerFocus *key,
+ GString *s)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (key));
- g_string_append_printf (s, "%s: focus-change %s is-focus: %d contains-focus: %d\n",
+ g_string_append_printf (s, "%s: focus-in is-focus: %d contains-focus: %d\n",
widget_name (widget),
- direction == GTK_CROSSING_IN ? "in" : "out",
- gtk_event_controller_key_is_focus (key),
- gtk_event_controller_key_contains_focus (key));
+ gtk_event_controller_focus_is_focus (key),
+ gtk_event_controller_focus_contains_focus (key));
+}
+
+static void
+focus_out (GtkEventControllerFocus *key,
+ GString *s)
+{
+ GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (key));
+
+ g_string_append_printf (s, "%s: focus-out is-focus: %d contains-focus: %d\n",
+ widget_name (widget),
+ gtk_event_controller_focus_is_focus (key),
+ gtk_event_controller_focus_contains_focus (key));
}
static void
@@ -32,8 +42,9 @@ add_controller (GtkWidget *widget, GString *s)
{
GtkEventController *controller;
- controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change), s);
+ controller = gtk_event_controller_focus_new ();
+ g_signal_connect (controller, "enter", G_CALLBACK (focus_in), s);
+ g_signal_connect (controller, "leave", G_CALLBACK (focus_out), s);
gtk_widget_add_controller (widget, controller);
}
@@ -107,8 +118,8 @@ test_window_focus (void)
g_print ("-> box\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
-"window: focus-change in is-focus: 0 contains-focus: 1\n"
-"box: focus-change in is-focus: 1 contains-focus: 1\n"
+"window: focus-in is-focus: 0 contains-focus: 1\n"
+"box: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@@ -118,12 +129,12 @@ test_window_focus (void)
g_print ("box -> entry1\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
-"box: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change in is-focus: 0 contains-focus: 1\n"
-"box: focus-change in is-focus: 0 contains-focus: 1\n"
-"box1: focus-change in is-focus: 0 contains-focus: 1\n"
-"entry1: focus-change in is-focus: 1 contains-focus: 1\n"
+"box: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-in is-focus: 0 contains-focus: 1\n"
+"box: focus-in is-focus: 0 contains-focus: 1\n"
+"box1: focus-in is-focus: 0 contains-focus: 1\n"
+"entry1: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@@ -136,14 +147,14 @@ test_window_focus (void)
g_print ("entry1 -> entry2\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
-"entry1: focus-change out is-focus: 0 contains-focus: 0\n"
-"box1: focus-change out is-focus: 0 contains-focus: 0\n"
-"box: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change in is-focus: 0 contains-focus: 1\n"
-"box: focus-change in is-focus: 0 contains-focus: 1\n"
-"box2: focus-change in is-focus: 0 contains-focus: 1\n"
-"entry2: focus-change in is-focus: 1 contains-focus: 1\n"
+"entry1: focus-out is-focus: 0 contains-focus: 0\n"
+"box1: focus-out is-focus: 0 contains-focus: 0\n"
+"box: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-in is-focus: 0 contains-focus: 1\n"
+"box: focus-in is-focus: 0 contains-focus: 1\n"
+"box2: focus-in is-focus: 0 contains-focus: 1\n"
+"entry2: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@@ -156,12 +167,12 @@ test_window_focus (void)
g_print ("entry2 -> box\n%s", s->str);
g_assert_cmpstr (s->str, ==,
-"entry2: focus-change out is-focus: 0 contains-focus: 0\n"
-"box2: focus-change out is-focus: 0 contains-focus: 0\n"
-"box: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change out is-focus: 0 contains-focus: 0\n"
-"window: focus-change in is-focus: 0 contains-focus: 1\n"
-"box: focus-change in is-focus: 1 contains-focus: 1\n"
+"entry2: focus-out is-focus: 0 contains-focus: 0\n"
+"box2: focus-out is-focus: 0 contains-focus: 0\n"
+"box: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-out is-focus: 0 contains-focus: 0\n"
+"window: focus-in is-focus: 0 contains-focus: 1\n"
+"box: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]