summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-03-08 09:55:27 -0500
committerMatthias Clasen <mclasen@redhat.com>2019-03-16 21:24:45 -0400
commit4f5a8207bca2c1b968c27ffd25cb76c770b7cf75 (patch)
tree5b0be20c0ff0d7d6d832264dfd54a3ecd5109546
parent2f1194c0c108274ee3ea2ecc7bd7921de317ab4b (diff)
downloadgtk+-4f5a8207bca2c1b968c27ffd25cb76c770b7cf75.tar.gz
key controller: Add focus properties
Add boolean properties, is-focus and contains-focus, that track whether the focus is in the widget itself or in one of its descendants.
-rw-r--r--gtk/gtkeventcontrollerkey.c131
1 files changed, 126 insertions, 5 deletions
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index 9f32cc9023..390ec4e2f4 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -46,6 +46,9 @@ struct _GtkEventControllerKey
GHashTable *pressed_keys;
const GdkEvent *current_event;
+
+ guint is_focus : 1;
+ guint contains_focus : 1;
};
struct _GtkEventControllerKeyClass
@@ -65,6 +68,14 @@ enum {
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)
@@ -79,6 +90,50 @@ 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 = FALSE;
+ break;
+ case GDK_NOTIFY_INFERIOR:
+ is_focus = focus_in;
+ contains_focus = !focus_in;
+ 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->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)
@@ -96,10 +151,13 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
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);
- if (gdk_event_get_focus_in (event, &focus_in) && focus_in)
+ update_focus (key, focus_in, detail);
+
+ if (focus_in)
g_signal_emit (controller, signals[FOCUS_IN], 0, mode, detail);
else
g_signal_emit (controller, signals[FOCUS_OUT], 0, mode, detail);
@@ -164,15 +222,76 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
}
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)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (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;
/**
+ * GtkEventControllerKey:is-focus:
+ *
+ * Whether focus is in the controllers widget itself,
+ * as opposed to in a descendent widget. See
+ * #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 in a descendant of the controllers widget.
+ * See #GtkEventControllerKey:is-focus.
+ *
+ * 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:
* @controller: the object which received the signal.
* @keyval: the pressed key.
@@ -247,8 +366,9 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
* @mode: crossing mode indicating what caused this change
* @detail: detail indication where the focus is coming from
*
- * This signal is emitted whenever the #GtkEventController:widget controlled
- * by the @controller is given the keyboard focus.
+ * 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"),
@@ -267,8 +387,9 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
* @mode: crossing mode indicating what caused this change
* @detail: detail indication where the focus is going
*
- * This signal is emitted whenever the #GtkEventController:widget controlled
- * by the @controller loses the keyboard focus.
+ * This signal is emitted whenever the widget controlled
+ * by the @controller (or one of its descendants) loses
+ * the keyboard focus.
*/
signals[FOCUS_OUT] =
g_signal_new (I_("focus-out"),