[gtk+/wip/baedert/progressbar: 1/18] widget: Add gtk_widget_insert_before/after



commit 5c36dec843f1caaed4163db137fce16dc8408bed
Author: Timm Bäder <mail baedert org>
Date:   Wed Apr 5 19:57:11 2017 +0200

    widget: Add gtk_widget_insert_before/after
    
    To insert a widget into the widget tree before or after a child widget
    of the soon-to-be parent.

 docs/reference/gtk/gtk4-sections.txt |    2 +
 gtk/gtkcssnode.c                     |    2 -
 gtk/gtkwidget.c                      |  190 ++++++++++++++++++++++++++++------
 gtk/gtkwidget.h                      |    8 ++
 4 files changed, 167 insertions(+), 35 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index df8b221..84229d0 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -4647,6 +4647,8 @@ gtk_widget_get_next_sibling
 gtk_widget_get_prev_sibling
 gtk_widget_get_first_child
 gtk_widget_get_last_child
+gtk_widget_insert_before
+gtk_widget_insert_after
 
 <SUBSECTION>
 gtk_widget_get_path
diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c
index 46ed213..d94c09d 100644
--- a/gtk/gtkcssnode.c
+++ b/gtk/gtkcssnode.c
@@ -842,8 +842,6 @@ gtk_css_node_insert_after (GtkCssNode *parent,
                            GtkCssNode *cssnode,
                            GtkCssNode *previous_sibling)
 {
-  g_return_if_fail (previous_sibling == NULL || previous_sibling->parent == parent);
-  g_return_if_fail (cssnode != previous_sibling);
 
   if (cssnode->previous_sibling == previous_sibling &&
       cssnode->parent == parent)
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index eb3761a..8267798 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -8374,37 +8374,27 @@ gtk_widget_is_sensitive (GtkWidget *widget)
   return !(widget->priv->state_flags & GTK_STATE_FLAG_INSENSITIVE);
 }
 
-/**
- * gtk_widget_set_parent:
- * @widget: a #GtkWidget
- * @parent: parent container
- *
- * This function is useful only when implementing subclasses of
- * #GtkContainer.
- * Sets the container as the parent of @widget, and takes care of
- * some details such as updating the state and style of the child
- * to reflect its new location. The opposite function is
- * gtk_widget_unparent().
- **/
-void
-gtk_widget_set_parent (GtkWidget *widget,
-                      GtkWidget *parent)
+
+/* Insert @widget into the children list of @parent,
+ * after @previous_child */
+static void
+gtk_widget_reposition_after (GtkWidget *widget,
+                             GtkWidget *parent,
+                             GtkWidget *previous_child)
 {
   GtkStateFlags parent_flags;
-  GtkWidgetPrivate *priv;
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GtkWidget *prev_parent;
   GtkStateData data;
 
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (GTK_IS_WIDGET (parent));
-  g_return_if_fail (widget != parent);
+  prev_parent = priv->parent;
 
-  priv = widget->priv;
-
-  if (priv->parent != NULL)
+  if (priv->parent != NULL && priv->parent != parent)
     {
       g_warning ("Can't set a parent on widget which has a parent");
       return;
     }
+
   if (_gtk_widget_is_toplevel (widget))
     {
       g_warning ("Can't set a parent on a toplevel widget");
@@ -8421,14 +8411,53 @@ gtk_widget_set_parent (GtkWidget *widget,
   gtk_widget_push_verify_invariants (widget);
 
   priv->parent = parent;
-  if (parent)
+
+  if (previous_child)
     {
-      priv->prev_sibling = parent->priv->last_child;
-      if (parent->priv->last_child)
-        parent->priv->last_child->priv->next_sibling = widget;
-      parent->priv->last_child = widget;
-      if (!parent->priv->first_child)
-        parent->priv->first_child = widget;
+      if (previous_child->priv->next_sibling)
+        previous_child->priv->next_sibling->priv->prev_sibling = widget;
+
+      if (priv->prev_sibling)
+        priv->prev_sibling->priv->next_sibling = priv->next_sibling;
+
+      if (priv->next_sibling)
+        priv->next_sibling->priv->prev_sibling = priv->prev_sibling;
+
+
+      if (parent->priv->first_child == widget)
+        parent->priv->first_child = priv->next_sibling;
+
+      if (parent->priv->last_child == widget)
+        parent->priv->last_child = priv->prev_sibling;
+
+      priv->prev_sibling = previous_child;
+      priv->next_sibling = previous_child->priv->next_sibling;
+      previous_child->priv->next_sibling = widget;
+
+      if (parent->priv->last_child == previous_child)
+        parent->priv->last_child = widget;
+      else if (parent->priv->last_child == widget)
+        parent->priv->last_child = priv->next_sibling;
+    }
+  else
+    {
+      /* Beginning */
+      if (parent->priv->last_child == widget)
+        {
+          parent->priv->last_child = priv->prev_sibling;
+          if (priv->prev_sibling)
+            priv->prev_sibling->priv->next_sibling = NULL;
+        }
+
+      priv->prev_sibling = NULL;
+      priv->next_sibling = parent->priv->first_child;
+      if (parent->priv->first_child)
+        parent->priv->first_child->priv->prev_sibling = widget;
+
+      parent->priv->first_child = widget;
+
+      if (parent->priv->last_child == NULL)
+        parent->priv->last_child = widget;
     }
 
   parent_flags = _gtk_widget_get_state_flags (parent);
@@ -8440,7 +8469,12 @@ gtk_widget_set_parent (GtkWidget *widget,
   gtk_widget_propagate_state (widget, &data);
 
   if (gtk_css_node_get_parent (widget->priv->cssnode) == NULL)
-    gtk_css_node_set_parent (widget->priv->cssnode, parent->priv->cssnode);
+    {
+      gtk_css_node_insert_after (parent->priv->cssnode,
+                                 priv->cssnode,
+                                 previous_child ? previous_child->priv->cssnode : NULL);
+    }
+
   if (priv->context)
     gtk_style_context_set_parent (priv->context,
                                   _gtk_widget_get_style_context (parent));
@@ -8448,7 +8482,7 @@ gtk_widget_set_parent (GtkWidget *widget,
   _gtk_widget_update_parent_muxer (widget);
 
   g_signal_emit (widget, widget_signals[PARENT_SET], 0, NULL);
-  if (priv->parent->priv->anchored)
+  if (priv->parent->priv->anchored && prev_parent == NULL)
     _gtk_widget_propagate_hierarchy_changed (widget, NULL);
   g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_PARENT]);
 
@@ -8461,8 +8495,8 @@ gtk_widget_set_parent (GtkWidget *widget,
       _gtk_widget_get_visible (widget))
     {
       if (_gtk_widget_get_child_visible (widget) &&
-         _gtk_widget_get_mapped (priv->parent))
-       gtk_widget_map (widget);
+          _gtk_widget_get_mapped (priv->parent))
+        gtk_widget_map (widget);
 
       gtk_widget_queue_resize (priv->parent);
     }
@@ -8489,6 +8523,31 @@ gtk_widget_set_parent (GtkWidget *widget,
 }
 
 /**
+ * gtk_widget_set_parent:
+ * @widget: a #GtkWidget
+ * @parent: parent container
+ *
+ * This function is useful only when implementing subclasses of
+ * #GtkContainer.
+ * Sets the container as the parent of @widget, and takes care of
+ * some details such as updating the state and style of the child
+ * to reflect its new location. The opposite function is
+ * gtk_widget_unparent().
+ **/
+void
+gtk_widget_set_parent (GtkWidget *widget,
+                       GtkWidget *parent)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GTK_IS_WIDGET (parent));
+  g_return_if_fail (_gtk_widget_get_parent (widget) == NULL);
+
+  gtk_widget_reposition_after (widget,
+                               parent,
+                               _gtk_widget_get_last_child (parent));
+}
+
+/**
  * gtk_widget_get_parent:
  * @widget: a #GtkWidget
  *
@@ -15634,6 +15693,71 @@ gtk_widget_get_prev_sibling (GtkWidget *widget)
   return widget->priv->prev_sibling;
 }
 
+/*
+ * @widget: a #GtkWidget
+ * @parent: the parent #GtkWidget to insert @widget into
+ * @previous_child: (nullable): the new previous sibling of @widget
+ *
+ * Inserts @widget into the child widget list of @parent.
+ * It will be placed after @previous_child, or at the beginning if @previous_child is %NULL.
+ *
+ * After calling this function, gtk_widget_get_prev_sibling(widget) will return @previous_child.
+ */
+void
+gtk_widget_insert_after (GtkWidget *widget,
+                         GtkWidget *parent,
+                         GtkWidget *previous_child)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GTK_IS_WIDGET (parent));
+  g_return_if_fail (previous_child == NULL || GTK_IS_WIDGET (previous_child));
+  g_return_if_fail (previous_child == NULL || _gtk_widget_get_parent (previous_child) == parent);
+
+  if (widget == previous_child ||
+      (previous_child && _gtk_widget_get_prev_sibling (widget) == previous_child))
+    return;
+
+  if (!previous_child && _gtk_widget_get_first_child (parent) == widget)
+    return;
+
+  gtk_widget_reposition_after (widget,
+                               parent,
+                               previous_child);
+}
+
+/*
+ * @widget: a #GtkWidget
+ * @parent: the parent #GtkWidget to insert @widget into
+ * @next_child: (nullable): the new next sibling of @widget or %NULL
+ *
+ * Inserts @widget into the child widget list of @parent.
+ * It will be placed before @next_child, or at the end if @next_child is %NULL.
+ *
+ * After calling this function, gtk_widget_get_next_sibling(widget) will return @next_child
+ * if @next_child was not %NULL.
+ */
+void
+gtk_widget_insert_before (GtkWidget *widget,
+                          GtkWidget *parent,
+                          GtkWidget *next_child)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (GTK_IS_WIDGET (parent));
+  g_return_if_fail (next_child == NULL || GTK_IS_WIDGET (next_child));
+  g_return_if_fail (next_child == NULL || _gtk_widget_get_parent (next_child) == parent);
+
+  if (widget == next_child ||
+      (next_child && _gtk_widget_get_next_sibling (widget) == next_child))
+    return;
+
+  if (!next_child && _gtk_widget_get_last_child (parent) == widget)
+    return;
+
+  gtk_widget_reposition_after (widget, parent,
+                               next_child ? _gtk_widget_get_prev_sibling (next_child) :
+                                            _gtk_widget_get_last_child (parent));
+}
+
 void
 gtk_widget_forall (GtkWidget   *widget,
                    GtkCallback  callback,
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index c1cbe20..837fbd0 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -1243,6 +1243,14 @@ GDK_AVAILABLE_IN_3_90
 GtkWidget *             gtk_widget_get_next_sibling     (GtkWidget *widget);
 GDK_AVAILABLE_IN_3_90
 GtkWidget *             gtk_widget_get_prev_sibling     (GtkWidget *widget);
+GDK_AVAILABLE_IN_3_92
+void                    gtk_widget_insert_after         (GtkWidget *widget,
+                                                         GtkWidget *parent,
+                                                         GtkWidget *previous_child);
+GDK_AVAILABLE_IN_3_92
+void                    gtk_widget_insert_before        (GtkWidget *widget,
+                                                         GtkWidget *parent,
+                                                         GtkWidget *next_child);
 GDK_AVAILABLE_IN_3_90
 void                    gtk_widget_set_focus_child      (GtkWidget *widget,
                                                          GtkWidget *child);


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