[gnome-shell/wip/fmuellner/first-last-child: 27/27] st: Only consider visible children for :first/:last-child



commit f8c81c9aa971216a6cdaab6c7f2973f25994559e
Author: Florian Müllner <fmuellner gnome org>
Date:   Tue Nov 27 02:21:37 2018 +0100

    st: Only consider visible children for :first/:last-child
    
    While mapping the :first/:last-child pseudo classes directly to the
    ClutterActor:first-child/:last-child properties allows for an easy
    implementation, it is unexpected that rules can appear to not have
    an effect because the selected child is hidden. GTK's behavior of
    applying the classes to visible children makes much more sense, so
    change our implementation to do the same.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/312

 src/st/st-widget.c | 165 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 127 insertions(+), 38 deletions(-)
---
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index 7c39b3585..2fa8ce200 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -80,11 +80,8 @@ struct _StWidgetPrivate
   ClutterActor *label_actor;
   gchar        *accessible_name;
 
-  /* Even though Clutter has first_child/last_child properties,
-   * we need to keep track of the old first/last children so
-   * that we can remove the pseudo classes on them. */
-  StWidget *prev_last_child;
-  StWidget *prev_first_child;
+  StWidget *last_visible_child;
+  StWidget *first_visible_child;
 
   StThemeNodePaintState paint_states[2];
   int current_paint_state : 2;
@@ -321,8 +318,8 @@ st_widget_dispose (GObject *gobject)
       priv->texture_file_changed_id = 0;
     }
 
-  g_clear_object (&priv->prev_first_child);
-  g_clear_object (&priv->prev_last_child);
+  g_clear_object (&priv->first_visible_child);
+  g_clear_object (&priv->last_visible_child);
 
   G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
 }
@@ -1446,6 +1443,64 @@ st_widget_get_style (StWidget *actor)
   return ST_WIDGET_PRIVATE (actor)->inline_style;
 }
 
+static void
+st_widget_set_first_visible_child (StWidget     *widget,
+                                   ClutterActor *actor)
+{
+  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
+
+  if (priv->first_visible_child == NULL && actor == NULL)
+    return;
+
+  if (priv->first_visible_child != NULL &&
+      CLUTTER_ACTOR (priv->first_visible_child) == actor)
+    return;
+
+  if (priv->first_visible_child != NULL)
+    {
+      st_widget_remove_style_pseudo_class (priv->first_visible_child, "first-child");
+      g_clear_object (&priv->first_visible_child);
+    }
+
+  if (actor == NULL)
+    return;
+
+  if (ST_IS_WIDGET (actor))
+    {
+      st_widget_add_style_pseudo_class (ST_WIDGET (actor), "first-child");
+      priv->first_visible_child = g_object_ref (ST_WIDGET (actor));
+    }
+}
+
+static void
+st_widget_set_last_visible_child (StWidget     *widget,
+                                  ClutterActor *actor)
+{
+  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
+
+  if (priv->last_visible_child == NULL && actor == NULL)
+    return;
+
+  if (priv->last_visible_child != NULL &&
+      CLUTTER_ACTOR (priv->last_visible_child) == actor)
+    return;
+
+  if (priv->last_visible_child != NULL)
+    {
+      st_widget_remove_style_pseudo_class (priv->last_visible_child, "last-child");
+      g_clear_object (&priv->last_visible_child);
+    }
+
+  if (actor == NULL)
+    return;
+
+  if (ST_IS_WIDGET (actor))
+    {
+      st_widget_add_style_pseudo_class (ST_WIDGET (actor), "last-child");
+      priv->last_visible_child = g_object_ref (ST_WIDGET (actor));
+    }
+}
+
 static void
 st_widget_name_notify (StWidget   *widget,
                        GParamSpec *pspec,
@@ -1470,56 +1525,89 @@ st_widget_reactive_notify (StWidget   *widget,
     st_widget_sync_hover(widget);
 }
 
+static ClutterActor *
+find_nearest_visible_backwards (ClutterActor *actor)
+{
+  ClutterActor *prev = actor;
+
+  while (prev != NULL && !clutter_actor_is_visible (prev))
+    prev = clutter_actor_get_previous_sibling (prev);
+  return prev;
+}
+
+static ClutterActor *
+find_nearest_visible_forward (ClutterActor *actor)
+{
+  ClutterActor *next = actor;
+
+  while (next != NULL && !clutter_actor_is_visible (next))
+    next = clutter_actor_get_next_sibling (next);
+  return next;
+}
+
 static void
-st_widget_first_child_notify (StWidget   *widget,
-                              GParamSpec *pspec,
-                              gpointer    data)
+st_widget_visible_notify (StWidget   *widget,
+                          GParamSpec *pspec,
+                          gpointer    data)
 {
-  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
-  ClutterActor *first_child;
+  ClutterActor *actor = CLUTTER_ACTOR (widget);
+  ClutterActor *parent = clutter_actor_get_parent (actor);
+
+  if (parent == NULL || !ST_IS_WIDGET (parent))
+    return;
 
-  if (priv->prev_first_child != NULL)
+  if (clutter_actor_is_visible (actor))
     {
-      st_widget_remove_style_pseudo_class (priv->prev_first_child, "first-child");
-      g_clear_object (&priv->prev_first_child);
+      ClutterActor *before, *after;
+
+      before = clutter_actor_get_previous_sibling (actor);
+      if (find_nearest_visible_backwards (before) == NULL)
+        st_widget_set_first_visible_child (ST_WIDGET (parent), actor);
+
+      after = clutter_actor_get_next_sibling (actor);
+      if (find_nearest_visible_forward (after) == NULL)
+        st_widget_set_last_visible_child (ST_WIDGET (parent), actor);
     }
+  else
+    {
+      if (st_widget_has_style_pseudo_class (widget, "first-child"))
+        {
+          ClutterActor *new_first;
 
-  first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
+          new_first = find_nearest_visible_forward (CLUTTER_ACTOR (widget));
+          st_widget_set_first_visible_child (ST_WIDGET (parent), new_first);
+        }
 
-  if (first_child == NULL)
-    return;
+      if (st_widget_has_style_pseudo_class (widget, "last-child"))
+        {
+          ClutterActor *new_last;
 
-  if (ST_IS_WIDGET (first_child))
-    {
-      st_widget_add_style_pseudo_class (ST_WIDGET (first_child), "first-child");
-      priv->prev_first_child = g_object_ref (ST_WIDGET (first_child));
+          new_last = find_nearest_visible_backwards (CLUTTER_ACTOR (widget));
+          st_widget_set_last_visible_child (ST_WIDGET (parent), new_last);
+        }
     }
 }
 
+static void
+st_widget_first_child_notify (StWidget   *widget,
+                              GParamSpec *pspec,
+                              gpointer    data)
+{
+  ClutterActor *first_child;
+
+  first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
+  st_widget_set_first_visible_child (widget, find_nearest_visible_forward (first_child));
+}
+
 static void
 st_widget_last_child_notify (StWidget   *widget,
                              GParamSpec *pspec,
                              gpointer    data)
 {
-  StWidgetPrivate *priv = st_widget_get_instance_private (widget);
   ClutterActor *last_child;
 
-  if (priv->prev_last_child != NULL)
-    {
-      st_widget_remove_style_pseudo_class (priv->prev_last_child, "last-child");
-      g_clear_object (&priv->prev_last_child);
-    }
-
   last_child = clutter_actor_get_last_child (CLUTTER_ACTOR (widget));
-
-  if (last_child == NULL)
-    return;
-
-  if (ST_IS_WIDGET (last_child))
-    {
-      st_widget_add_style_pseudo_class (ST_WIDGET (last_child), "last-child");
-      priv->prev_last_child = g_object_ref (ST_WIDGET (last_child));
-    }
+  st_widget_set_last_visible_child (widget, find_nearest_visible_backwards (last_child));
 }
 
 static void
@@ -1536,6 +1624,7 @@ st_widget_init (StWidget *actor)
   g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
   g_signal_connect (actor, "notify::reactive", G_CALLBACK (st_widget_reactive_notify), NULL);
 
+  g_signal_connect (actor, "notify::visible", G_CALLBACK (st_widget_visible_notify), NULL);
   g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL);
   g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);
   priv->texture_file_changed_id = g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",


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