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



commit 4d0a742d64bd7e47015ef23b443d9d32e9225313
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 eea5f7f3b..f5ca8928a 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;
@@ -322,8 +319,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);
 }
@@ -1488,6 +1485,64 @@ st_widget_get_resource_scale (StWidget *widget,
                                            resource_scale);
 }
 
+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,
@@ -1529,56 +1584,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
@@ -1596,6 +1684,7 @@ st_widget_init (StWidget *actor)
   g_signal_connect (actor, "notify::resource-scale", G_CALLBACK (st_widget_resource_scale_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]