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



commit f24d034cf5e25430fe4a798994e70e125a98c1c4
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 db984ac9b..6c049257f 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;
@@ -348,8 +345,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);
 }
@@ -1473,6 +1470,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,
@@ -1497,56 +1552,89 @@ st_widget_reactive_notify (StWidget   *widget,
     st_widget_sync_hover(widget);
 }
 
+static ClutterActor *
+find_previous_visible (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_next_visible (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_previous_visible (before) == NULL)
+        st_widget_set_first_visible_child (ST_WIDGET (parent), actor);
+
+      after = clutter_actor_get_next_sibling (actor);
+      if (find_next_visible (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_next_visible (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_previous_visible (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_next_visible (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_previous_visible (last_child));
 }
 
 static void
@@ -1563,6 +1651,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]