[gtk+] boxgadget: Add



commit acc534ebfa2a3c292aca590c8a116a6340d2274d
Author: Benjamin Otte <otte redhat com>
Date:   Wed Dec 23 04:09:30 2015 +0100

    boxgadget: Add
    
    Adds a GtkBoxGadget that is a Gadget that behaves like a GtkBox.
    
    Use this gadget to implement the notebook base gadget.

 gtk/Makefile.am           |    2 +
 gtk/gtkboxgadget.c        |  511 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkboxgadgetprivate.h |   74 +++++++
 gtk/gtknotebook.c         |  334 +++++++-----------------------
 4 files changed, 658 insertions(+), 263 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index ff259d1..527037a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -365,6 +365,7 @@ gtk_private_h_sources =             \
        gtkbitmaskprivateimpl.h \
        gtkbookmarksmanager.h   \
        gtkboxprivate.h         \
+       gtkboxgadgetprivate.h   \
        gtkbuilderprivate.h     \
        gtkbuiltiniconprivate.h \
        gtkbuttonprivate.h      \
@@ -600,6 +601,7 @@ gtk_base_c_sources =                \
        gtkbookmarksmanager.c   \
        gtkborder.c             \
        gtkbox.c                \
+       gtkboxgadget.c          \
        gtkbuildable.c          \
        gtkbuilder.c            \
        gtkbuilderparser.c      \
diff --git a/gtk/gtkboxgadget.c b/gtk/gtkboxgadget.c
new file mode 100644
index 0000000..6ea8529
--- /dev/null
+++ b/gtk/gtkboxgadget.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkboxgadgetprivate.h"
+
+#include "gtkcssnodeprivate.h"
+#include "gtkmain.h"
+#include "gtkprivate.h"
+#include "gtksizerequest.h"
+#include "gtkwidgetprivate.h"
+
+typedef struct _GtkBoxGadgetPrivate GtkBoxGadgetPrivate;
+struct _GtkBoxGadgetPrivate {
+  GtkOrientation orientation;
+  GArray *children;
+};
+
+typedef gboolean (* ComputeExpandFunc) (GObject *object, GtkOrientation orientation);
+
+typedef struct _GtkBoxGadgetChild GtkBoxGadgetChild;
+struct _GtkBoxGadgetChild {
+  GObject *object;
+  ComputeExpandFunc compute_expand;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GtkBoxGadget, gtk_box_gadget, GTK_TYPE_CSS_GADGET,
+                         G_ADD_PRIVATE (GtkBoxGadget))
+
+static gboolean
+gtk_box_gadget_child_is_visible (GObject *child)
+{
+  if (GTK_IS_WIDGET (child))
+    return gtk_widget_get_visible (GTK_WIDGET (child));
+  else
+    return gtk_css_gadget_get_visible (GTK_CSS_GADGET (child));
+}
+
+static void
+gtk_box_gadget_measure_child (GObject        *child,
+                              GtkOrientation  orientation,
+                              gint            for_size,
+                              gint           *minimum,
+                              gint           *natural,
+                              gint           *minimum_baseline,
+                              gint           *natural_baseline)
+{
+  if (GTK_IS_WIDGET (child))
+    {
+      _gtk_widget_get_preferred_size_for_size (GTK_WIDGET (child),
+                                               orientation,
+                                               for_size,
+                                               minimum, natural,
+                                               minimum_baseline, natural_baseline);
+    }
+  else
+    {
+      gtk_css_gadget_get_preferred_size (GTK_CSS_GADGET (child),
+                                         orientation,
+                                         for_size,
+                                         minimum, natural,
+                                         minimum_baseline, natural_baseline);
+    }
+}
+
+static void
+gtk_box_gadget_distribute (GtkBoxGadget     *gadget,
+                           gint              size,
+                           GtkRequestedSize *sizes)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+  guint i, n_expand;
+
+  n_expand = 0;
+
+  for (i = 0 ; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      gtk_box_gadget_measure_child (child->object,
+                                    priv->orientation,
+                                    -1, 
+                                    &sizes[i].minimum_size, &sizes[i].natural_size,
+                                    NULL, NULL);
+      if (gtk_box_gadget_child_is_visible (child->object) &&
+          child->compute_expand (child->object, priv->orientation))
+        n_expand++;
+      size -= sizes[i].minimum_size;
+    }
+
+  g_assert (size >= 0);
+
+  size = gtk_distribute_natural_allocation (size, priv->children->len, sizes);
+
+  if (size <= 0 || n_expand == 0)
+    return;
+
+  for (i = 0 ; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      if (!gtk_box_gadget_child_is_visible (child->object) ||
+          !child->compute_expand (child->object, priv->orientation))
+        continue;
+
+      sizes[i].minimum_size += size / n_expand;
+      /* distribute all pixels, even if there's a remainder */
+      size -= size / n_expand;
+      n_expand--;
+    }
+}
+
+static void
+gtk_box_gadget_measure_orientation (GtkCssGadget   *gadget,
+                                    GtkOrientation  orientation,
+                                    gint            for_size,
+                                    gint           *minimum,
+                                    gint           *natural,
+                                    gint           *minimum_baseline,
+                                    gint           *natural_baseline)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+  gint child_min, child_nat;
+  guint i;
+
+  *minimum = 0;
+  *natural = 0;
+
+  for (i = 0 ; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      gtk_box_gadget_measure_child (child->object,
+                                    orientation,
+                                    for_size,
+                                    &child_min, &child_nat,
+                                    NULL, NULL);
+
+      *minimum += child_min;
+      *natural += child_nat;
+    }
+}
+
+static void
+gtk_box_gadget_measure_opposite (GtkCssGadget   *gadget,
+                                 GtkOrientation  orientation,
+                                 gint            for_size,
+                                 gint           *minimum,
+                                 gint           *natural,
+                                 gint           *minimum_baseline,
+                                 gint           *natural_baseline)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+  int child_min, child_nat, child_min_baseline, child_nat_baseline;
+  int total_min, above_min, below_min, total_nat, above_nat, below_nat;
+  GtkRequestedSize *sizes;
+  guint i;
+
+  if (for_size >= 0)
+    {
+      sizes = g_newa (GtkRequestedSize, priv->children->len);
+      gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), for_size, sizes);
+    }
+
+  above_min = below_min = above_nat = below_nat = -1;
+  total_min = total_nat = 0;
+
+  for (i = 0 ; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      gtk_box_gadget_measure_child (child->object,
+                                    orientation,
+                                    for_size >= 0 ? sizes[i].minimum_size : for_size,
+                                    &child_min, &child_nat,
+                                    &child_min_baseline, &child_nat_baseline);
+
+      if (child_min_baseline >= 0)
+        {
+          above_min = MAX (above_min, child_min - child_min_baseline);
+          below_min = MAX (below_min, child_min_baseline);
+          above_nat = MAX (above_nat, child_nat - child_nat_baseline);
+          below_nat = MAX (below_nat, child_nat_baseline);
+        }
+      else
+        {
+          total_min = MAX (total_min, child_min);
+          total_nat = MAX (total_nat, child_nat);
+        }
+    }
+
+  if (above_min >= 0)
+    {
+      total_min = MAX (total_min, above_min + below_min);
+      total_nat = MAX (total_nat, above_nat + below_nat);
+      /* assume GTK_BASELINE_POSITION_CENTER for now */
+      *minimum_baseline = above_min + (total_min - (above_min + below_min)) / 2;
+      *natural_baseline = above_nat + (total_nat - (above_nat + below_nat)) / 2;
+    }
+
+  *minimum = total_min;
+  *natural = total_nat;
+}
+
+static void
+gtk_box_gadget_get_preferred_size (GtkCssGadget   *gadget,
+                                   GtkOrientation  orientation,
+                                   gint            for_size,
+                                   gint           *minimum,
+                                   gint           *natural,
+                                   gint           *minimum_baseline,
+                                   gint           *natural_baseline)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+
+  if (priv->orientation == orientation)
+    gtk_box_gadget_measure_orientation (gadget, orientation, for_size, minimum, natural, minimum_baseline, 
natural_baseline);
+  else
+    gtk_box_gadget_measure_opposite (gadget, orientation, for_size, minimum, natural, minimum_baseline, 
natural_baseline);
+}
+
+static void
+gtk_box_gadget_allocate_child (GObject        *child,
+                               GtkAllocation *allocation,
+                               int            baseline,
+                               GtkAllocation *out_clip)
+{
+  if (GTK_IS_WIDGET (child))
+    {
+      gtk_widget_size_allocate_with_baseline (GTK_WIDGET (child),
+                                              allocation,
+                                              baseline);
+      gtk_widget_get_clip (GTK_WIDGET (child), out_clip);
+    }
+  else
+    {
+      gtk_css_gadget_allocate (GTK_CSS_GADGET (child),
+                               allocation,
+                               baseline,
+                               out_clip);
+    }
+}
+
+static void
+gtk_box_gadget_allocate (GtkCssGadget        *gadget,
+                         const GtkAllocation *allocation,
+                         int                  baseline,
+                         GtkAllocation       *out_clip)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+  GtkRequestedSize *sizes;
+  GtkAllocation child_allocation, child_clip;
+  guint i;
+
+  child_allocation = *allocation;
+  sizes = g_newa (GtkRequestedSize, priv->children->len);
+
+  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->width, sizes);
+      for (i = 0 ; i < priv->children->len; i++)
+        {
+          GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+          child_allocation.width = sizes[i].minimum_size;
+          gtk_box_gadget_allocate_child (child->object, &child_allocation, baseline, &child_clip);
+          if (i == 0)
+            *out_clip = child_clip;
+          else
+            gdk_rectangle_union (out_clip, &child_clip, out_clip);
+          child_allocation.x += sizes[i].minimum_size;
+        }
+    }
+  else
+    {
+      gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->height, sizes);
+      for (i = 0 ; i < priv->children->len; i++)
+        {
+          GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+          child_allocation.height = sizes[i].minimum_size;
+          gtk_box_gadget_allocate_child (child->object, &child_allocation, -1, &child_clip);
+          if (i == 0)
+            *out_clip = child_clip;
+          else
+            gdk_rectangle_union (out_clip, &child_clip, out_clip);
+          child_allocation.y += sizes[i].minimum_size;
+        }
+    }
+}
+
+static gboolean
+gtk_box_gadget_draw (GtkCssGadget *gadget,
+                     cairo_t      *cr,
+                     int           x,
+                     int           y,
+                     int           width,
+                     int           height)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
+  guint i;
+
+  for (i = 0 ; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      if (GTK_IS_WIDGET (child->object))
+        {
+          gtk_container_propagate_draw (GTK_CONTAINER (gtk_css_gadget_get_owner (gadget)),
+                                        GTK_WIDGET (child->object),
+                                        cr);
+        }
+      else
+        {
+          gtk_css_gadget_draw (GTK_CSS_GADGET (child->object),
+                               cr);
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_box_gadget_finalize (GObject *object)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (object));
+
+  g_array_free (priv->children, TRUE);
+
+  G_OBJECT_CLASS (gtk_box_gadget_parent_class)->finalize (object);
+}
+
+static void
+gtk_box_gadget_class_init (GtkBoxGadgetClass *klass)
+{
+  GtkCssGadgetClass *gadget_class = GTK_CSS_GADGET_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtk_box_gadget_finalize;
+
+  gadget_class->get_preferred_size = gtk_box_gadget_get_preferred_size;
+  gadget_class->allocate = gtk_box_gadget_allocate;
+  gadget_class->draw = gtk_box_gadget_draw;
+}
+
+static void
+gtk_box_gadget_clear_child (gpointer data)
+{
+  GtkBoxGadgetChild *child = data;
+
+  g_object_unref (child->object);
+}
+
+static void
+gtk_box_gadget_init (GtkBoxGadget *gadget)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
+
+  priv->children = g_array_new (FALSE, FALSE, sizeof (GtkBoxGadgetChild));
+  g_array_set_clear_func (priv->children, gtk_box_gadget_clear_child);
+}
+
+GtkCssGadget *
+gtk_box_gadget_new_for_node (GtkCssNode *node,
+                               GtkWidget  *owner)
+{
+  return g_object_new (GTK_TYPE_BOX_GADGET,
+                       "node", node,
+                       "owner", owner,
+                       NULL);
+}
+
+GtkCssGadget *
+gtk_box_gadget_new (const char   *name,
+                      GtkWidget    *owner,
+                      GtkCssGadget *parent,
+                      GtkCssGadget *next_sibling)
+{
+  GtkCssNode *node;
+  GtkCssGadget *result;
+
+  node = gtk_css_node_new ();
+  gtk_css_node_set_name (node, g_intern_string (name));
+  if (parent)
+    gtk_css_node_insert_before (gtk_css_gadget_get_node (parent),
+                                node,
+                                next_sibling ? gtk_css_gadget_get_node (next_sibling) : NULL);
+
+  result = gtk_box_gadget_new_for_node (node, owner);
+
+  g_object_unref (node);
+
+  return result;
+}
+
+void
+gtk_box_gadget_set_orientation (GtkBoxGadget   *gadget,
+                                GtkOrientation  orientation)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
+
+  priv->orientation = orientation;
+}
+
+static void
+gtk_box_gadget_insert_object (GtkBoxGadget      *gadget,
+                              int                pos,
+                              GObject           *object,
+                              ComputeExpandFunc  compute_expand_func)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
+  GtkBoxGadgetChild child;
+
+  child.object = g_object_ref (object);
+  child.compute_expand = compute_expand_func;
+
+  if (pos < 0 || pos >= priv->children->len)
+    g_array_append_val (priv->children, child);
+  else
+    g_array_insert_val (priv->children, pos, child);
+}
+
+void
+gtk_box_gadget_insert_widget (GtkBoxGadget           *gadget,
+                              int                     pos,
+                              GtkWidget              *widget)
+{
+  gtk_box_gadget_insert_object (gadget,
+                                pos,
+                                G_OBJECT (widget),
+                                (ComputeExpandFunc) gtk_widget_compute_expand);
+}
+
+void
+gtk_box_gadget_remove_object (GtkBoxGadget *gadget,
+                              GObject      *object)
+{
+  GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
+  guint i;
+
+  for (i = 0; i < priv->children->len; i++)
+    {
+      GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
+
+      if (child->object == object)
+        {
+          g_array_remove_index (priv->children, i);
+          break;
+        }
+    }
+}
+
+void
+gtk_box_gadget_remove_widget (GtkBoxGadget *gadget,
+                              GtkWidget    *widget)
+{
+  gtk_box_gadget_remove_object (gadget, G_OBJECT (widget));
+}
+
+static gboolean
+only_horizontal (GObject        *object,
+                 GtkOrientation  orientation)
+{
+  return orientation == GTK_ORIENTATION_HORIZONTAL;
+}
+
+static gboolean
+only_vertical (GObject        *object,
+               GtkOrientation  orientation)
+{
+  return orientation == GTK_ORIENTATION_VERTICAL;
+}
+
+void
+gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
+                              int           pos,
+                              GtkCssGadget *cssgadget,
+                              gboolean      hexpand,
+                              gboolean      vexpand)
+{
+  gtk_box_gadget_insert_object (gadget,
+                                pos,
+                                G_OBJECT (cssgadget),
+                                hexpand ? (vexpand ? (ComputeExpandFunc) gtk_true : only_horizontal)
+                                        : (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false));
+}
+
+void
+gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
+                              GtkCssGadget *cssgadget)
+{
+  gtk_box_gadget_remove_object (gadget, G_OBJECT (cssgadget));
+}
+
diff --git a/gtk/gtkboxgadgetprivate.h b/gtk/gtkboxgadgetprivate.h
new file mode 100644
index 0000000..ce64e41
--- /dev/null
+++ b/gtk/gtkboxgadgetprivate.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_BOX_GADGET_PRIVATE_H__
+#define __GTK_BOX_GADGET_PRIVATE_H__
+
+#include "gtk/gtkcssgadgetprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_BOX_GADGET           (gtk_box_gadget_get_type ())
+#define GTK_BOX_GADGET(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_BOX_GADGET, GtkBoxGadget))
+#define GTK_BOX_GADGET_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_BOX_GADGET, GtkBoxGadgetClass))
+#define GTK_IS_BOX_GADGET(obj)        (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_BOX_GADGET))
+#define GTK_IS_BOX_GADGET_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_BOX_GADGET))
+#define GTK_BOX_GADGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_BOX_GADGET, 
GtkBoxGadgetClass))
+
+typedef struct _GtkBoxGadget           GtkBoxGadget;
+typedef struct _GtkBoxGadgetClass      GtkBoxGadgetClass;
+
+struct _GtkBoxGadget
+{
+  GtkCssGadget parent;
+};
+
+struct _GtkBoxGadgetClass
+{
+  GtkCssGadgetClass  parent_class;
+};
+
+GType                   gtk_box_gadget_get_type                 (void) G_GNUC_CONST;
+
+GtkCssGadget *          gtk_box_gadget_new                      (const char             *name,
+                                                                 GtkWidget              *owner,
+                                                                 GtkCssGadget           *parent,
+                                                                 GtkCssGadget           *next_sibling);
+GtkCssGadget *          gtk_box_gadget_new_for_node             (GtkCssNode             *node,
+                                                                 GtkWidget              *owner);
+
+void                    gtk_box_gadget_set_orientation          (GtkBoxGadget           *gadget,
+                                                                 GtkOrientation          orientation);
+
+void                    gtk_box_gadget_insert_widget            (GtkBoxGadget           *gadget,
+                                                                 int                     pos,
+                                                                 GtkWidget              *widget);
+void                    gtk_box_gadget_remove_widget            (GtkBoxGadget           *gadget,
+                                                                 GtkWidget              *widget);
+void                    gtk_box_gadget_insert_gadget            (GtkBoxGadget           *gadget,
+                                                                 int                     pos,
+                                                                 GtkCssGadget           *cssgadget,
+                                                                 gboolean                hexpand,
+                                                                 gboolean                vexpand);
+void                    gtk_box_gadget_remove_gadget            (GtkBoxGadget           *gadget,
+                                                                 GtkCssGadget           *cssgadget);
+
+G_END_DECLS
+
+#endif /* __GTK_BOX_GADGET_PRIVATE_H__ */
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 38dab30..727f221 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -43,6 +43,7 @@
 #include "gtkbuildable.h"
 #include "gtktypebuiltins.h"
 #include "gtkwidgetpath.h"
+#include "gtkboxgadgetprivate.h"
 #include "gtkcsscustomgadgetprivate.h"
 #include "gtkcssstylepropertyprivate.h"
 #include "gtksizerequest.h"
@@ -521,26 +522,6 @@ static gboolean gtk_notebook_draw_stack      (GtkCssGadget     *gadget,
                                               int               width,
                                               int               height,
                                               gpointer          data);
-static void gtk_notebook_measure_contents    (GtkCssGadget     *gadget,
-                                              GtkOrientation    orientation,
-                                              gint              for_size,
-                                              gint             *minimum,
-                                              gint             *natural,
-                                              gint             *minimum_baseline,
-                                              gint             *natural_baseline,
-                                              gpointer          data);
-static void gtk_notebook_allocate_contents   (GtkCssGadget     *gadget,
-                                              const GtkAllocation *allocation,
-                                              int               baseline,
-                                              GtkAllocation    *out_clip,
-                                              gpointer          data);
-static gboolean gtk_notebook_draw_contents   (GtkCssGadget     *gadget,
-                                              cairo_t          *cr,
-                                              int               x,
-                                              int               y,
-                                              int               width,
-                                              int               height,
-                                              gpointer          data);
 
 /*** GtkNotebook Private Functions ***/
 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
@@ -603,6 +584,8 @@ static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
 static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
                                               GtkMenu          *menu);
 
+static void gtk_notebook_update_tab_pos      (GtkNotebook      *notebook);
+
 /*** GtkNotebook Private Setters ***/
 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
                                                             gboolean overload,
@@ -1350,14 +1333,10 @@ gtk_notebook_init (GtkNotebook *notebook)
   gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
 
   widget_node = gtk_widget_get_css_node (GTK_WIDGET (notebook));
-  priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node,
-                                                     GTK_WIDGET (notebook),
-                                                     gtk_notebook_measure_contents,
-                                                     gtk_notebook_allocate_contents,
-                                                     gtk_notebook_draw_contents,
-                                                     NULL,
-                                                     NULL);
+  priv->gadget = gtk_box_gadget_new_for_node (widget_node,
+                                              GTK_WIDGET (notebook));
   gtk_css_gadget_add_class (priv->gadget, GTK_STYLE_CLASS_FRAME);
+  gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
 
   priv->stack_gadget = gtk_css_custom_gadget_new ("stack",
                                                   GTK_WIDGET (notebook),
@@ -1369,6 +1348,7 @@ gtk_notebook_init (GtkNotebook *notebook)
                                                   NULL,
                                                   NULL);
   gtk_css_gadget_set_state (priv->stack_gadget, gtk_css_node_get_state (widget_node));
+  gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE);
 
   priv->header_gadget = gtk_css_custom_gadget_new ("header",
                                                    GTK_WIDGET (notebook),
@@ -1381,6 +1361,8 @@ gtk_notebook_init (GtkNotebook *notebook)
                                                    NULL);
   gtk_css_gadget_add_class (priv->header_gadget, GTK_STYLE_CLASS_TOP);
   gtk_css_gadget_set_state (priv->header_gadget, gtk_css_node_get_state (widget_node));
+  gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
+  gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
 
   priv->tabs_node = gtk_css_node_new ();
   gtk_css_node_set_name (priv->tabs_node, I_("tabs"));
@@ -1995,7 +1977,7 @@ gtk_notebook_realize (GtkWidget *widget)
 
   gtk_widget_set_realized (widget, TRUE);
 
-  gtk_notebook_get_event_window_position (notebook, &event_window_pos);
+  gtk_css_gadget_get_border_allocation (priv->header_gadget, &event_window_pos, NULL);
 
   window = gtk_widget_get_parent_window (widget);
   gtk_widget_set_window (widget, window);
@@ -2280,115 +2262,6 @@ gtk_notebook_measure_stack (GtkCssGadget   *gadget,
     }
 }
 
-static GtkOrientation
-get_orientation_from_tab_pos (GtkNotebook *notebook)
-{
-  GtkPositionType tab_pos = notebook->priv->tab_pos;
-
-  if (tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT)
-    return GTK_ORIENTATION_HORIZONTAL;
-  else
-    return GTK_ORIENTATION_VERTICAL;
-}
-
-static void
-gtk_notebook_distribute_content_size (GtkNotebook *notebook,
-                                      gint         size,
-                                      gint        *header_size,
-                                      gint        *stack_size)
-{
-  GtkNotebookPrivate *priv = notebook->priv;
-  GtkOrientation orientation = get_orientation_from_tab_pos (notebook);
-  GtkRequestedSize request[2];
-
-  if (size < 0)
-    {
-      *header_size = -1;
-      *stack_size = -1;
-      return;
-    }
-
-  gtk_css_gadget_get_preferred_size (priv->header_gadget,
-                                     orientation,
-                                     -1,
-                                     &request[0].minimum_size, &request[0].natural_size,
-                                     NULL, NULL);
-  gtk_css_gadget_get_preferred_size (priv->stack_gadget,
-                                     orientation,
-                                     -1,
-                                     &request[1].minimum_size, &request[1].natural_size,
-                                     NULL, NULL);
-
-  size = gtk_distribute_natural_allocation (size - request[0].minimum_size - request[1].minimum_size,
-                                            G_N_ELEMENTS (request),
-                                            request);
-
-  *header_size = request[0].minimum_size;
-  *stack_size = request[1].minimum_size + size;
-}
-
-static void
-gtk_notebook_measure_contents (GtkCssGadget   *gadget,
-                               GtkOrientation  orientation,
-                               gint            size,
-                               gint           *minimum,
-                               gint           *natural,
-                               gint           *minimum_baseline,
-                               gint           *natural_baseline,
-                               gpointer        unused)
-{
-  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkNotebookPrivate *priv = notebook->priv;
-  gint stack_min, stack_nat, header_min, header_nat;
-
-  if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
-    {
-      gtk_css_gadget_get_preferred_size (priv->stack_gadget,
-                                         orientation,
-                                         size,
-                                         minimum, natural,
-                                         NULL, NULL);
-
-    }
-  else if (orientation == get_orientation_from_tab_pos (notebook))
-    {
-      gtk_css_gadget_get_preferred_size (priv->header_gadget,
-                                         orientation,
-                                         size,
-                                         &header_min, &header_nat,
-                                         NULL, NULL);
-      gtk_css_gadget_get_preferred_size (priv->stack_gadget,
-                                         orientation,
-                                         size,
-                                         &stack_min, &stack_nat,
-                                         NULL, NULL);
-
-      *minimum = header_min + stack_min;
-      *natural = header_nat + stack_nat;
-    }
-  else
-    {
-      gint header_size, stack_size;
-
-      gtk_notebook_distribute_content_size (notebook, size, &header_size, &stack_size);
-
-      gtk_css_gadget_get_preferred_size (priv->header_gadget,
-                                         orientation,
-                                         header_size,
-                                         &header_min, &header_nat,
-                                         NULL, NULL);
-      gtk_css_gadget_get_preferred_size (priv->stack_gadget,
-                                         orientation,
-                                         stack_size,
-                                         &stack_min, &stack_nat,
-                                         NULL, NULL);
-
-      *minimum = MAX (header_min, stack_min);
-      *natural = MAX (header_nat, stack_nat);
-    }
-}
-
 static void
 gtk_notebook_get_preferred_width_for_height (GtkWidget *widget,
                                              gint       height,
@@ -2518,106 +2391,39 @@ gtk_notebook_allocate_stack (GtkCssGadget        *gadget,
 }
 
 static void
-gtk_notebook_allocate_contents (GtkCssGadget        *gadget,
-                                const GtkAllocation *allocation,
-                                int                  baseline,
-                                GtkAllocation       *out_clip,
-                                gpointer             unused)
+gtk_notebook_size_allocate (GtkWidget     *widget,
+                            GtkAllocation *allocation)
 {
-  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
   GtkNotebookPrivate *priv = notebook->priv;
-  GtkAllocation stack_allocation, header_allocation;
-  
-  stack_allocation = *allocation;
-
-  if (!priv->show_tabs || !gtk_notebook_has_current_page (notebook))
-    {
-      gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, out_clip);
-      if (gtk_widget_get_realized (widget))
-        gdk_window_hide (priv->event_window);
-    }
-  else
-    {
-      GtkAllocation stack_clip, header_clip;
-
-      header_allocation = stack_allocation;
-
-      switch (get_effective_tab_pos (notebook))
-        {
-        case GTK_POS_TOP:
-          gtk_notebook_distribute_content_size (notebook,
-                                                stack_allocation.height,
-                                                &header_allocation.height,
-                                                &stack_allocation.height);
-          stack_allocation.y += header_allocation.height;
-          break;
-
-        case GTK_POS_BOTTOM:
-          gtk_notebook_distribute_content_size (notebook,
-                                                stack_allocation.height,
-                                                &header_allocation.height,
-                                                &stack_allocation.height);
-          header_allocation.y += stack_allocation.height;
-          break;
-
-        case GTK_POS_LEFT:
-          gtk_notebook_distribute_content_size (notebook,
-                                                stack_allocation.width,
-                                                &header_allocation.width,
-                                                &stack_allocation.width);
-          stack_allocation.x += header_allocation.width;
-          break;
+  GtkAllocation clip;
 
-        case GTK_POS_RIGHT:
-          gtk_notebook_distribute_content_size (notebook,
-                                                stack_allocation.width,
-                                                &header_allocation.width,
-                                                &stack_allocation.width);
-          header_allocation.x += stack_allocation.width;
-          break;
+  gtk_widget_set_allocation (widget, allocation);
 
-        default:
-          g_assert_not_reached ();
-          break;
-        }
+  gtk_css_gadget_allocate (priv->gadget,
+                           allocation,
+                           gtk_widget_get_allocated_baseline (widget),
+                           &clip);
 
-      gtk_css_gadget_allocate (priv->header_gadget, &header_allocation, -1, &header_clip);
-      gtk_css_gadget_allocate (priv->stack_gadget, &stack_allocation, -1, &stack_clip);
+  gtk_widget_set_clip (widget, &clip);
 
-      gdk_rectangle_union (&stack_clip, &header_clip, out_clip);
+  if (gtk_widget_get_realized (widget))
+    {
+      GdkRectangle position;
 
-      if (gtk_widget_get_realized (widget))
+      if (gtk_notebook_get_event_window_position (notebook, &position))
         {
-          GtkAllocation position;
-          gtk_css_gadget_get_border_allocation (priv->header_gadget, &position, NULL);
           gdk_window_move_resize (priv->event_window,
                                   position.x, position.y,
                                   position.width, position.height);
           if (gtk_widget_get_mapped (GTK_WIDGET (notebook)))
             gdk_window_show_unraised (priv->event_window);
         }
+      else
+        gdk_window_hide (priv->event_window);
     }
 }
 
-static void
-gtk_notebook_size_allocate (GtkWidget     *widget,
-                            GtkAllocation *allocation)
-{
-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkNotebookPrivate *priv = notebook->priv;
-  GtkAllocation clip;
-
-  gtk_widget_set_allocation (widget, allocation);
-
-  gtk_css_gadget_allocate (priv->gadget,
-                           allocation,
-                           gtk_widget_get_allocated_baseline (widget),
-                           &clip);
-
-  gtk_widget_set_clip (widget, &clip);
-}
-
 static gboolean
 gtk_notebook_draw_stack (GtkCssGadget *gadget,
                          cairo_t      *cr,
@@ -2640,40 +2446,6 @@ gtk_notebook_draw_stack (GtkCssGadget *gadget,
 }
 
 static gboolean
-gtk_notebook_draw_contents (GtkCssGadget *gadget,
-                            cairo_t      *cr,
-                            int           x,
-                            int           y,
-                            int           width,
-                            int           height,
-                            gpointer      unused)
-{
-  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkNotebookPrivate *priv = notebook->priv;
-  GdkWindow *window;
-
-  window = gtk_widget_get_window (widget);
-  if (gtk_cairo_should_draw_window (cr, window))
-    {
-      gtk_css_gadget_draw (priv->stack_gadget, cr);
-
-      if (priv->show_tabs && gtk_notebook_has_current_page (notebook))
-        gtk_css_gadget_draw (priv->header_gadget, cr);
-    }
-
-  if (gtk_notebook_has_current_page (notebook) && priv->operation == DRAG_OPERATION_REORDER &&
-      gtk_cairo_should_draw_window (cr, priv->drag_window))
-    {
-      gtk_notebook_draw_tab (notebook,
-                             priv->cur_page,
-                             cr);
-    }
-
-  return FALSE;
-}
-
-static gboolean
 gtk_notebook_draw (GtkWidget *widget,
                    cairo_t   *cr)
 {
@@ -4800,19 +4572,22 @@ page_visible_cb (GtkWidget  *child,
         gtk_widget_set_visible (parent, gtk_widget_get_visible (child));
     }
 
-  if (priv->cur_page == page &&
-      !gtk_widget_get_visible (child))
+  if (priv->cur_page == page)
     {
-      list = g_list_find (priv->children, priv->cur_page);
-      if (list)
+      if (!gtk_widget_get_visible (child))
         {
-          next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
-          if (!next)
-            next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
-        }
+          list = g_list_find (priv->children, priv->cur_page);
+          if (list)
+            {
+              next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
+              if (!next)
+                next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
+            }
 
-      if (next)
-        gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
+          if (next)
+            gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next));
+        }
+      gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs && gtk_notebook_has_current_page 
(notebook));
     }
   
   if (!gtk_notebook_has_current_page (notebook) && gtk_widget_get_visible (child))
@@ -6632,6 +6407,7 @@ gtk_notebook_real_switch_page (GtkNotebook     *notebook,
   priv->cur_page = page;
   gtk_css_node_set_state (page->cssnode,
                           gtk_css_node_get_state (page->cssnode) | GTK_STATE_FLAG_ACTIVE);
+  gtk_css_gadget_set_visible (priv->header_gadget, priv->show_tabs);
 
   if (!priv->focus_tab ||
       priv->focus_tab->data != (gpointer) priv->cur_page)
@@ -7418,11 +7194,14 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
           else
             gtk_widget_hide (page->tab_label);
         }
+      gtk_css_gadget_set_visible (priv->header_gadget,
+                                  gtk_notebook_has_current_page (notebook));
     }
   else
     {
       gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
       gtk_notebook_update_labels (notebook);
+      gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
     }
 
   for (i = 0; i < N_ACTION_WIDGETS; i++)
@@ -7431,6 +7210,7 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
         gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
     }
 
+  gtk_notebook_update_tab_pos (notebook);
   gtk_widget_reset_style (GTK_WIDGET (notebook));
   gtk_widget_queue_resize (GTK_WIDGET (notebook));
 
@@ -7476,6 +7256,34 @@ gtk_notebook_update_tab_pos (GtkNotebook *notebook)
       else
         gtk_css_gadget_remove_class (priv->header_gadget, tab_pos_names[i]);
     }
+
+  gtk_box_gadget_remove_gadget (GTK_BOX_GADGET (priv->gadget), priv->header_gadget);
+  switch (tab_pos)
+    {
+    case GTK_POS_TOP:
+      if (priv->show_tabs)
+        gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
+      gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
+      break;
+
+    case GTK_POS_BOTTOM:
+      if (priv->show_tabs)
+        gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
+      gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
+      break;
+
+    case GTK_POS_LEFT:
+      if (priv->show_tabs)
+        gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
+      gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
+      break;
+
+    case GTK_POS_RIGHT:
+      if (priv->show_tabs)
+        gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
+      gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
+      break;
+    }
 }
 
 /**



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