[gtk/wip/matthiasc/focus2: 2/50] Redo focus handling



commit fc9caeaae78d43e6b49fcc4c23651720e9b3a95b
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Mar 2 00:54:56 2019 -0500

    Redo focus handling
    
    GtkWindow has a focus_widget that points to the current input focus.
    GtkWidget has a focus_child that points to the child that contains
    the input focus. Following the focus_child chain from the toplevel
    always leads to the focus_widget. We never unset focus_child, we only
    set it. We bubble focus change events.

 gtk/gtkwidget.c | 109 ++------------------------------------------
 gtk/gtkwindow.c | 139 ++++++++++++++------------------------------------------
 2 files changed, 38 insertions(+), 210 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 56f26387a9..a7085f9525 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -5335,88 +5335,16 @@ gtk_widget_grab_focus (GtkWidget *widget)
   if (!gtk_widget_is_sensitive (widget))
     return;
 
-  g_object_ref (widget);
   GTK_WIDGET_GET_CLASS (widget)->grab_focus (widget);
-  g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]);
-  g_object_unref (widget);
-}
-
-static void
-reset_focus_recurse (GtkWidget *widget,
-                    gpointer   data)
-{
-  gtk_widget_set_focus_child (widget, NULL);
-
-  gtk_widget_forall (widget,
-                     reset_focus_recurse,
-                     NULL);
 }
 
 static void
 gtk_widget_real_grab_focus (GtkWidget *focus_widget)
 {
   GtkWidget *toplevel;
-  GtkWidget *widget;
-
-  /* clear the current focus setting, break if the current widget
-   * is the focus widget's parent, since containers above that will
-   * be set by the next loop.
-   */
-  toplevel = _gtk_widget_get_toplevel (focus_widget);
-  if (_gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel))
-    {
-      widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
-
-      if (widget == focus_widget)
-        {
-          /* We call _gtk_window_internal_set_focus() here so that the
-           * toplevel window can request the focus if necessary.
-           * This is needed when the toplevel is a GtkPlug
-           */
-          if (!gtk_widget_has_focus (widget))
-            _gtk_window_internal_set_focus (GTK_WINDOW (toplevel), focus_widget);
-
-          return;
-        }
-
-      if (widget)
-        {
-          GtkWidget *common_ancestor = gtk_widget_common_ancestor (widget, focus_widget);
 
-          if (widget != common_ancestor)
-            {
-              while (widget->priv->parent)
-                {
-                  widget = widget->priv->parent;
-                  gtk_widget_set_focus_child (widget, NULL);
-                  if (widget == common_ancestor)
-                    break;
-                }
-            }
-        }
-    }
-  else if (toplevel != focus_widget)
-    {
-      /* gtk_widget_grab_focus() operates on a tree without window...
-       * actually, this is very questionable behavior.
-       */
-
-      gtk_widget_forall (toplevel,
-                         reset_focus_recurse,
-                         NULL);
-    }
-
-  /* now propagate the new focus up the widget tree and finally
-   * set it on the window
-   */
-  widget = focus_widget;
-  while (widget->priv->parent)
-    {
-      gtk_widget_set_focus_child (widget->priv->parent, widget);
-      widget = widget->priv->parent;
-    }
-  if (GTK_IS_WINDOW (widget))
-    _gtk_window_internal_set_focus (GTK_WINDOW (widget), focus_widget);
+  toplevel = gtk_widget_get_toplevel (focus_widget);
+  gtk_window_set_focus (GTK_WINDOW (toplevel), focus_widget);
 }
 
 static gboolean
@@ -5555,10 +5483,7 @@ gtk_widget_real_move_focus (GtkWidget         *widget,
   GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
 
   if (widget != toplevel && GTK_IS_WINDOW (toplevel))
-    {
-      g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0,
-                     direction);
-    }
+    g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0, direction);
 }
 
 static gboolean
@@ -11722,22 +11647,17 @@ gtk_widget_send_focus_change (GtkWidget *widget,
                               GdkEvent  *event)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
-  gboolean res;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
   g_return_val_if_fail (event != NULL && event->any.type == GDK_FOCUS_CHANGE, FALSE);
 
-  g_object_ref (widget);
-
   priv->has_focus = event->focus_change.in;
 
-  res = gtk_widget_event (widget, event);
+  gtk_propagate_event (widget, event);
 
   g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]);
 
-  g_object_unref (widget);
-
-  return res;
+  return TRUE;
 }
 
 /**
@@ -13459,26 +13379,7 @@ gtk_widget_set_focus_child (GtkWidget *widget,
       g_return_if_fail (gtk_widget_get_parent (child) == widget);
     }
 
-  if (priv->focus_child)
-    gtk_widget_unset_state_flags (priv->focus_child,
-                                  GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_FOCUS_VISIBLE);
-
-  if (child)
-    {
-      GtkWidget *toplevel;
-      GtkStateFlags flags = GTK_STATE_FLAG_FOCUSED;
-
-      toplevel = _gtk_widget_get_toplevel (widget);
-      if (!GTK_IS_WINDOW (toplevel) || gtk_window_get_focus_visible (GTK_WINDOW (toplevel)))
-        flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
-
-      gtk_widget_set_state_flags (child, flags, FALSE);
-    }
-
   g_set_object (&priv->focus_child, child);
-
-  if (GTK_IS_CONTAINER (widget))
-    gtk_container_set_focus_child (GTK_CONTAINER (widget), child);
 }
 
 /**
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 600e96e515..10e80d195d 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -2787,52 +2787,9 @@ void
 gtk_window_set_focus (GtkWindow *window,
                      GtkWidget *focus)
 {
-  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-  GtkWidget *parent;
-
-  g_return_if_fail (GTK_IS_WINDOW (window));
-
-  if (focus)
-    {
-      g_return_if_fail (GTK_IS_WIDGET (focus));
-      g_return_if_fail (gtk_widget_get_can_focus (focus));
-
-      if (!gtk_widget_get_visible (GTK_WIDGET (window)))
-        priv->initial_focus = focus;
-      else
-        gtk_widget_grab_focus (focus);
-    }
-  else
-    {
-      /* Clear the existing focus chain, so that when we focus into
-       * the window again, we start at the beginnning.
-       */
-      GtkWidget *widget = priv->focus_widget;
-      if (widget)
-       {
-         while ((parent = _gtk_widget_get_parent (widget)))
-           {
-             widget = parent;
-              gtk_widget_set_focus_child (widget, NULL);
-           }
-       }
-      
-      _gtk_window_internal_set_focus (window, NULL);
-    }
-}
-
-void
-_gtk_window_internal_set_focus (GtkWindow *window,
-                               GtkWidget *focus)
-{
-  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-
   g_return_if_fail (GTK_IS_WINDOW (window));
 
-  priv->initial_focus = NULL;
-  if ((priv->focus_widget != focus) ||
-      (focus && !gtk_widget_has_focus (focus)))
-    g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
+  g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
 }
 
 /**
@@ -7326,79 +7283,49 @@ gtk_window_move_focus (GtkWidget        *widget,
 }
 
 static void
-gtk_window_real_set_focus (GtkWindow *window,
-                          GtkWidget *focus)
+unset_focus_widget (GtkWindow *window)
 {
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-  GtkWidget *old_focus = priv->focus_widget;
+  GtkWidget *f;
 
-  if (old_focus)
-    {
-      g_object_ref (old_focus);
-      g_object_freeze_notify (G_OBJECT (old_focus));
-    }
-  if (focus)
-    {
-      g_object_ref (focus);
-      g_object_freeze_notify (G_OBJECT (focus));
-    }
+  for (f = priv->focus_widget; f; f = gtk_widget_get_parent (f))
+    gtk_widget_unset_state_flags (f, GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_FOCUS_VISIBLE);
 
   if (priv->focus_widget)
-    {
-      if (gtk_widget_get_receives_default (priv->focus_widget) &&
-         (priv->focus_widget != priv->default_widget))
-        {
-          _gtk_widget_set_has_default (priv->focus_widget, FALSE);
-
-         if (priv->default_widget)
-            _gtk_widget_set_has_default (priv->default_widget, TRUE);
-       }
+    do_focus_change (priv->focus_widget, FALSE);
+  g_set_object (&priv->focus_widget, NULL);
+}
 
-      priv->focus_widget = NULL;
+static void
+set_focus_widget (GtkWindow *window,
+                  GtkWidget *focus)
+{
+  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
+  GtkWidget *f;
+  GtkStateFlags flags = GTK_STATE_FLAG_FOCUSED;
 
-      if (priv->is_active)
-       do_focus_change (old_focus, FALSE);
+  if (gtk_window_get_focus_visible (window))
+    flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
 
-      g_object_notify (G_OBJECT (old_focus), "is-focus");
-    }
-
-  /* The above notifications may have set a new focus widget,
-   * if so, we don't want to override it.
-   */
-  if (focus && !priv->focus_widget)
+  for (f = focus; f; f = gtk_widget_get_parent (f))
     {
-      priv->focus_widget = focus;
-
-      if (gtk_widget_get_receives_default (priv->focus_widget) &&
-         (priv->focus_widget != priv->default_widget))
-       {
-         if (gtk_widget_get_can_default (priv->focus_widget))
-            _gtk_widget_set_has_default (priv->focus_widget, TRUE);
-
-         if (priv->default_widget)
-            _gtk_widget_set_has_default (priv->default_widget, FALSE);
-       }
-
-      if (priv->is_active)
-       do_focus_change (priv->focus_widget, TRUE);
-
-      /* It's possible for do_focus_change() above to have callbacks
-       * that clear priv->focus_widget here.
-       */
-      if (priv->focus_widget)
-        g_object_notify (G_OBJECT (priv->focus_widget), "is-focus");
+      GtkWidget *parent = gtk_widget_get_parent (f);
+      gtk_widget_set_state_flags (f, flags, FALSE);
+      if (parent)
+        gtk_widget_set_focus_child (parent, f);
     }
 
-  if (old_focus)
-    {
-      g_object_thaw_notify (G_OBJECT (old_focus));
-      g_object_unref (old_focus);
-    }
-  if (focus)
-    {
-      g_object_thaw_notify (G_OBJECT (focus));
-      g_object_unref (focus);
-    }
+  g_set_object (&priv->focus_widget, focus);
+  if (priv->focus_widget)
+    do_focus_change (priv->focus_widget, TRUE);
+}
+
+static void
+gtk_window_real_set_focus (GtkWindow *window,
+                          GtkWidget *focus)
+{
+  unset_focus_widget (window);
+  set_focus_widget (window, focus);
 }
 
 static void


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