[gtk/wip/matthiasc/focus3: 32/40] key controller: Add focus properties



commit 4f5a8207bca2c1b968c27ffd25cb76c770b7cf75
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Mar 8 09:55:27 2019 -0500

    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.

 gtk/gtkeventcontrollerkey.c | 131 ++++++++++++++++++++++++++++++++++++++++++--
 1 file 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);
@@ -163,6 +221,29 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
   return handled;
 }
 
+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)
 {
@@ -170,8 +251,46 @@ 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;
 
+  /**
+   * 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.
@@ -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"),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]