Don't forget files when committing, stoopeed
authorEmmanuele Bassi <ebassi@openedhand.com>
Thu, 7 Jun 2007 19:23:04 +0000 (19:23 +0000)
committerEmmanuele Bassi <ebassi@openedhand.com>
Thu, 7 Jun 2007 19:23:04 +0000 (19:23 +0000)
clutter/clutter-container.c [new file with mode: 0644]
clutter/clutter-container.h [new file with mode: 0644]
clutter/clutter-layout.c [new file with mode: 0644]
clutter/clutter-layout.h [new file with mode: 0644]

diff --git a/clutter/clutter-container.c b/clutter/clutter-container.c
new file mode 100644 (file)
index 0000000..c277aca
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * ClutterContainer: Generic actor container interface.
+ * Author: Emmanuele Bassi <ebassi@openedhand.com>
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <glib-object.h>
+
+#include "clutter-container.h"
+
+#include "clutter-debug.h"
+#include "clutter-main.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+#include "clutter-enum-types.h"
+
+/**
+ * SECTION:clutter-container
+ * @short_description: An interface for implementing container actors
+ *
+ * #ClutterContainer is an interface for writing actors containing other
+ * #ClutterActor<!-- -->s. It provides a standard API for adding, removing
+ * and iterating on every contained actor.
+ *
+ * An actor implementing #ClutterContainer is #ClutterGroup.
+ *
+ * #ClutterContainer is available since Clutter 0.4
+ */
+
+enum
+{
+  ACTOR_ADDED,
+  ACTOR_REMOVED,
+
+  LAST_SIGNAL
+};
+
+static guint container_signals[LAST_SIGNAL] = { 0, };
+
+static void
+clutter_container_base_init (gpointer g_iface)
+{
+  static gboolean initialised = FALSE;
+
+  if (!initialised)
+    {
+      GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+      
+      initialised = TRUE;
+
+      /**
+       * ClutterContainer::actor-added:
+       * @container: the actor which received the signal
+       * @actor: the new child that has been added to @container
+       *
+       * The ::actor-added signal is emitted each time an actor
+       * has been added to @container.
+       *
+       * Since: 0.4
+       */
+      container_signals[ACTOR_ADDED] =
+        g_signal_new ("actor-added",
+                      iface_type,
+                      G_SIGNAL_RUN_FIRST,
+                      G_STRUCT_OFFSET (ClutterContainerIface, actor_added),
+                      NULL, NULL,
+                      clutter_marshal_VOID__OBJECT,
+                      G_TYPE_NONE, 1,
+                      CLUTTER_TYPE_ACTOR);
+      /**
+       * ClutterContainer::actor-removed:
+       * @container: the actor which received the signal
+       * @actor: the child that has been removed from @container
+       *
+       * The ::actor-removed signal is emitted each time an actor
+       * is removed from @container.
+       *
+       * Since: 0.4
+       */
+      container_signals[ACTOR_REMOVED] =
+        g_signal_new ("actor-removed",
+                      iface_type,
+                      G_SIGNAL_RUN_FIRST,
+                      G_STRUCT_OFFSET (ClutterContainerIface, actor_removed),
+                      NULL, NULL,
+                      clutter_marshal_VOID__OBJECT,
+                      G_TYPE_NONE, 1,
+                      CLUTTER_TYPE_ACTOR);
+    }
+}
+
+GType
+clutter_container_get_type (void)
+{
+  static GType container_type = 0;
+
+  if (G_UNLIKELY (!container_type))
+    {
+      GTypeInfo container_info =
+      {
+        sizeof (ClutterContainerIface),
+        clutter_container_base_init,
+        NULL, /* iface_finalize */
+      };
+
+      container_type = g_type_register_static (G_TYPE_INTERFACE,
+                                               "ClutterContainer",
+                                               &container_info, 0);
+
+      g_type_interface_add_prerequisite (container_type, CLUTTER_TYPE_ACTOR);
+    }
+
+  return container_type;
+}
+
+/**
+ * clutter_container_add:
+ * @container: a #ClutterContainer
+ * @first_actor: the first #ClutterActor to add
+ * @Varargs: %NULL terminated list of actors to add
+ *
+ * Adds a list of #ClutterActor<!-- -->s to @container. Each time and
+ * actor is added, the "actor-added" signal is emitted. Each actor should
+ * be parented to @container, which takes a reference on the actor. You
+ * cannot add a #ClutterActor to more than one #ClutterContainer.
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_add (ClutterContainer *container,
+                       ClutterActor     *first_actor,
+                       ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
+
+  va_start (var_args, first_actor);
+  clutter_container_add_valist (container, first_actor, var_args);
+  va_end (var_args);
+}
+
+/**
+ * clutter_container_add_actor:
+ * @container: a #ClutterContainer
+ * @actor: the first #ClutterActor to add
+ *
+ * Adds a #ClutterActor to @container. This function will emit the
+ * "actor-added" signal is emitted. The actor should be parented to
+ * @container. You cannot add a #ClutterActor to more than one
+ * #ClutterContainer.
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_add_actor (ClutterContainer *container,
+                             ClutterActor     *actor)
+{
+  ClutterActor *parent;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+
+  parent = clutter_actor_get_parent (actor);
+  if (parent)
+    {
+      g_warning ("Attempting to add actor of type `%s' to a "
+                "group of type `%s', but the actor has already "
+                "a parent of type `%s'.",
+                g_type_name (G_OBJECT_TYPE (actor)),
+                g_type_name (G_OBJECT_TYPE (container)),
+                g_type_name (G_OBJECT_TYPE (parent)));
+      return;
+    }
+
+  CLUTTER_CONTAINER_GET_IFACE (container)->add (container, actor);
+}
+
+/**
+ * clutter_container_add:
+ * @container: a #ClutterContainer
+ * @first_actor: the first #ClutterActor to add
+ * @var_args: list of actors to add, followed by %NULL
+ *
+ * Alternative va_list version of clutter_container_add().
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_add_valist (ClutterContainer *container,
+                              ClutterActor     *first_actor,
+                              va_list           var_args)
+{
+  ClutterActor *actor;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
+
+  actor = first_actor;
+  while (actor)
+    {
+      clutter_container_add_actor (container, actor);
+      actor = va_arg (var_args, ClutterActor*);
+    }
+}
+
+/**
+ * clutter_container_remove:
+ * @container: a #ClutterContainer
+ * @first_actor: first #ClutterActor to remove
+ * @Varargs: a %NULL-terminated list of actors to remove
+ *
+ * Removes a %NULL terminated list of #ClutterActor<!-- -->s from
+ * @container. Each actor should be unparented, so if you want to keep it
+ * around you must hold a reference to it yourself, using g_object_ref().
+ * Each time an actor is removed, the "actor-removed" signal is
+ * emitted by @container.
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_remove (ClutterContainer *container,
+                          ClutterActor     *first_actor,
+                          ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
+
+  va_start (var_args, first_actor);
+  clutter_container_remove_valist (container, first_actor, var_args);
+  va_end (var_args);
+}
+
+/**
+ * clutter_container_remove_actor:
+ * @container: a #ClutterContainer
+ * @actor: a #ClutterActor
+ *
+ * Removes @actor from @container. The actor should be unparented, so
+ * if you want to keep it around you must hold a reference to it
+ * yourself, using g_object_ref(). When the actor has been removed,
+ * the "actor-removed" signal is emitted by @container.
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_remove_actor (ClutterContainer *container,
+                                ClutterActor     *actor)
+{
+  ClutterActor *parent;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+
+  parent = clutter_actor_get_parent (actor);
+  if (parent != CLUTTER_ACTOR (container))
+    {
+      g_warning ("Attempting to remove actor of type `%s' from "
+                "group of class `%s', but the group is not the "
+                "actor's parent.",
+                g_type_name (G_OBJECT_TYPE (actor)),
+                g_type_name (G_OBJECT_TYPE (container)));
+      return;
+    }
+
+  CLUTTER_CONTAINER_GET_IFACE (container)->remove (container, actor);
+}
+
+/**
+ * clutter_container_remove_valist:
+ * @container: a #ClutterContainer
+ * @first_actor: the first #ClutterActor to add
+ * @var_args: list of actors to remove, followed by %NULL
+ *
+ * Alternative va_list version of clutter_container_remove().
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_remove_valist (ClutterContainer *container,
+                                 ClutterActor     *first_actor,
+                                 va_list           var_args)
+{
+  ClutterActor *actor;
+
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (CLUTTER_IS_ACTOR (first_actor));
+
+  actor = first_actor;
+  while (actor)
+    {
+      clutter_container_remove_actor (container, actor);
+
+      actor = va_arg (var_args, ClutterActor*);
+    }
+}
+
+static void
+get_children_cb (ClutterActor *child,
+                 gpointer      data)
+{
+  GList **children = data;
+
+  *children = g_list_prepend (*children, child);
+}
+
+/**
+ * clutter_container_get_children:
+ * @container: a #ClutterContainer
+ *
+ * Retrieves all the children of @container.
+ *
+ * Return value: a list of #ClutterActor<!-- -->s. Use g_list_free()
+ *   on the returned list when done.
+ *
+ * Since: 0.4
+ */
+GList *
+clutter_container_get_children (ClutterContainer *container)
+{
+  GList *retval;
+
+  g_return_val_if_fail (CLUTTER_IS_CONTAINER (container), NULL);
+
+  retval = NULL;
+  clutter_container_foreach (container, get_children_cb, &retval);
+
+  return g_list_reverse (retval);
+}
+
+/**
+ * clutter_container_foreach:
+ * @container: a #ClutterContainer
+ * @callback: a function to be called for each child
+ * @user_data: data to be passed to the function, or %NULL
+ *
+ * Calls @callback for each child of @container.
+ *
+ * Since: 0.4
+ */
+void
+clutter_container_foreach (ClutterContainer *container,
+                           ClutterCallback   callback,
+                           gpointer          user_data)
+{
+  g_return_if_fail (CLUTTER_IS_CONTAINER (container));
+  g_return_if_fail (callback != NULL);
+
+  CLUTTER_CONTAINER_GET_IFACE (container)->foreach (container, callback, user_data);
+}
+
diff --git a/clutter/clutter-container.h b/clutter/clutter-container.h
new file mode 100644 (file)
index 0000000..4d59c9b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * ClutterContainer: Generic actor container interface.
+ * Author: Emmanuele Bassi <ebassi@openedhand.com>
+ */
+
+#ifndef __CLUTTER_CONTAINER_H__
+#define __CLUTTER_CONTAINER_H__
+
+#include <clutter/clutter-actor.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_CONTAINER                  (clutter_container_get_type ())
+#define CLUTTER_CONTAINER(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainer))
+#define CLUTTER_IS_CONTAINER(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONTAINER))
+#define CLUTTER_CONTAINER_GET_IFACE(obj)        (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_CONTAINER, ClutterContainerIface))
+
+typedef struct _ClutterContainer        ClutterContainer; /* dummy */
+typedef struct _ClutterContainerIface   ClutterContainerIface;
+
+struct _ClutterContainerIface
+{
+  GTypeInterface g_iface;
+
+  void (* add)           (ClutterContainer *container,
+                          ClutterActor     *actor);
+  void (* remove)        (ClutterContainer *container,
+                          ClutterActor     *actor);
+  void (* foreach)       (ClutterContainer *container,
+                          ClutterCallback   callback,
+                          gpointer          user_data);
+  
+  /* signals */
+  void (* actor_added)   (ClutterContainer *container,
+                          ClutterActor     *actor);
+  void (* actor_removed) (ClutterContainer *container,
+                          ClutterActor     *actor);
+
+  /* padding, for future expansion */
+  void (*_clutter_reserved1) (void);
+  void (*_clutter_reserved2) (void);
+  void (*_clutter_reserved3) (void);
+  void (*_clutter_reserved4) (void);
+  void (*_clutter_reserved5) (void);
+  void (*_clutter_reserved6) (void);
+  void (*_clutter_reserved7) (void);
+  void (*_clutter_reserved8) (void);
+};
+
+GType  clutter_container_get_type      (void) G_GNUC_CONST;
+
+void   clutter_container_add           (ClutterContainer *container,
+                                        ClutterActor     *first_actor,
+                                        ...) G_GNUC_NULL_TERMINATED;
+void   clutter_container_add_actor     (ClutterContainer *container,
+                                        ClutterActor     *actor);
+void   clutter_container_add_valist    (ClutterContainer *container,
+                                        ClutterActor     *first_actor,
+                                        va_list           varargs);
+void   clutter_container_remove        (ClutterContainer *container,
+                                        ClutterActor     *first_actor,
+                                        ...) G_GNUC_NULL_TERMINATED;
+void   clutter_container_remove_actor  (ClutterContainer *container,
+                                        ClutterActor     *actor);
+void   clutter_container_remove_valist (ClutterContainer *container,
+                                        ClutterActor     *first_actor,
+                                        va_list           varargs);
+GList *clutter_container_get_children  (ClutterContainer *container);
+void   clutter_container_foreach       (ClutterContainer *container,
+                                        ClutterCallback   callback,
+                                        gpointer          user_data);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_CONTAINER_H__ */
diff --git a/clutter/clutter-layout.c b/clutter/clutter-layout.c
new file mode 100644 (file)
index 0000000..cbd1e28
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * ClutterLayout: interface to be implemented by actors providing
+ *                extended layouts.
+ *
+ * Author: Emmanuele Bassi <ebassi@openedhand.com>
+ */
+
+#include "config.h"
+
+#include "clutter-layout.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+#include "clutter-units.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+
+#define MAX_TUNE_REQUESTS       3
+
+/**
+ * SECTION:clutter-layout
+ * @short_description: An interface for implementing layouts
+ *
+ * #ClutterLayout is an interface that #ClutterActor<!-- -->s might
+ * implement to provide complex or extended layouts. The default
+ * size allocation of a #ClutterActor inside a #ClutterGroup is to
+ * make the group size allocation grow enough to contain the actor.
+ * A #ClutterActor implementing the #ClutterLayout interface will
+ * be queried for its size when it is added to a #ClutterGroup subclass
+ * that honours the #ClutterLayout interface; the resulting size
+ * allocation will depend on the #ClutterLayoutFlags that the actor
+ * supports.
+ *
+ * There are various types of layout available for actors implementing
+ * the #ClutterLayout interface: %CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT will
+ * ask the actor for its width given the height allocated by the
+ * container; %CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH will ask the actor for
+ * its height given the width allocated by the container. These two
+ * layout types are especially useful for labels and unidirectional
+ * container types, like vertical and horizontal boxes.
+ *
+ * Another layout available is %CLUTTER_LAYOUT_NATURAL, which will
+ * query the actor for its natural (default) width and height; the
+ * container actor will then try to allocate as much as it can,
+ * and might resort to scaling the actor to fit the allocation. This
+ * layout type is suited for #ClutterTexture<!-- -->s and shapes.
+ *
+ * Finally, the %CLUTTER_LAYOUT_TUNABLE is an iterative layout. An actor
+ * will be queried multiple times until it's satisfied with the size
+ * given.
+ *
+ * A #ClutterGroup subclass that honours the #ClutterLayout interface
+ * should check whether an actor is implementing this interface when
+ * adding it, by using the %CLUTTER_IS_LAYOUT type check macro. If the
+ * actor does implement the interface, the #ClutterGroup should get
+ * the supported layouts using clutter_layout_get_layout_flags() and
+ * verify which layout is compatible with the group's own layout; for
+ * instance, vertical containers should check for actors implementing the
+ * %CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT layout management, while horizontal
+ * containers should check for actors implementing the
+ * %CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH layout management. If the actor
+ * satisfies the layout requirements, the container actor should query
+ * the actor for a geometry request using the appropriate function and
+ * allocate space for the newly added actor accordingly.
+ *
+ * #ClutterLayout is available since Clutter 0.4
+ */
+
+static void
+clutter_layout_base_init (gpointer g_iface)
+{
+  static gboolean initialised = FALSE;
+
+  if (G_UNLIKELY (!initialised))
+    {
+      initialised = TRUE;
+
+      /**
+       * ClutterLayout:layout-flags:
+       *
+       * The layout types that the #ClutterLayout supports.
+       *
+       * Since: 0.4
+       */
+      g_object_interface_install_property (g_iface,
+                                           g_param_spec_flags ("layout-flags",
+                                                               "Layout Flags",
+                                                               "Supported layouts",
+                                                               CLUTTER_TYPE_LAYOUT_FLAGS,
+                                                               CLUTTER_LAYOUT_NONE,
+                                                               CLUTTER_PARAM_READABLE));
+  }
+}
+
+GType
+clutter_layout_get_type (void)
+{
+  static GType layout_type = 0;
+
+  if (!layout_type)
+    {
+      GTypeInfo layout_info =
+      {
+        sizeof (ClutterLayoutIface),
+        clutter_layout_base_init,
+        NULL,
+      };
+      
+      layout_type = g_type_register_static (G_TYPE_INTERFACE, "ClutterLayout",
+                                            &layout_info, 0);
+      g_type_interface_add_prerequisite (layout_type, CLUTTER_TYPE_ACTOR);
+    }
+
+  return layout_type;
+}
+
+/*
+ * Public API
+ */
+
+/**
+ * clutter_layout_get_layout_flags:
+ * @layout: a #ClutterLayout
+ *
+ * Retrieves the supported layout types from the #ClutterLayout
+ *
+ * Return value: bitwise or of #ClutterLayoutFlags
+ *
+ * Since: 0.4
+ */
+ClutterLayoutFlags
+clutter_layout_get_layout_flags (ClutterLayout *layout)
+{
+  g_return_val_if_fail (CLUTTER_IS_LAYOUT (layout), CLUTTER_LAYOUT_NONE);
+
+  if (CLUTTER_LAYOUT_GET_IFACE (layout)->get_layout_flags)
+    return CLUTTER_LAYOUT_GET_IFACE (layout)->get_layout_flags (layout);
+
+  return CLUTTER_LAYOUT_NONE;
+}
+
+/**
+ * clutter_layout_width_for_height:
+ * @layout: a #ClutterLayout
+ * @width: return location for the width
+ * @height: height allocated by the parent
+ *
+ * Queries a #ClutterLayout actor for its width with a known height.
+ *
+ * Since: 0.4
+ */
+void
+clutter_layout_width_for_height (ClutterLayout *layout,
+                                 gint          *width,
+                                 gint           height)
+{
+  ClutterLayoutFlags layout_type;
+
+  g_return_if_fail (CLUTTER_IS_LAYOUT (layout));
+
+  layout_type = clutter_layout_get_layout_flags (layout);
+  if (layout_type & CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT)
+    {
+      ClutterUnit u_width, u_height;
+
+      u_height = CLUTTER_UNITS_FROM_INT (height);
+      CLUTTER_LAYOUT_GET_IFACE (layout)->width_for_height (layout,
+                                                           &u_width,
+                                                           u_height);
+      
+      if (width)
+        *width = CLUTTER_UNITS_TO_INT (u_width);
+    }
+  else
+    {
+      g_warning ("Actor queried for width with a given height, but "
+                 "actors of type `%s' do not support width-for-height "
+                 "layouts.",
+                 g_type_name (G_OBJECT_TYPE (layout)));
+
+      if (width)
+        *width = -1;
+    }
+}
+
+/**
+ * clutter_layout_height_for_width:
+ * @layout: a #ClutterLayout
+ * @width: width allocated by the parent
+ * @height: return location for the height
+ *
+ * Queries a #ClutterLayout actor for its height with a known width.
+ *
+ * Since: 0.4
+ */
+void
+clutter_layout_height_for_width (ClutterLayout *layout,
+                                 gint           width,
+                                 gint          *height)
+{
+  ClutterLayoutFlags layout_type;
+
+  g_return_if_fail (CLUTTER_IS_LAYOUT (layout));
+
+  layout_type = clutter_layout_get_layout_flags (layout);
+  if (layout_type & CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH)
+    {
+      ClutterUnit u_width, u_height;
+
+      u_width = CLUTTER_UNITS_FROM_INT (width);
+      CLUTTER_LAYOUT_GET_IFACE (layout)->height_for_width (layout,
+                                                           u_width,
+                                                           &u_height);
+      
+      if (height)
+        *height = CLUTTER_UNITS_TO_INT (u_height);
+    }
+  else
+    {
+      g_warning ("Actor queried for height with a given width, but "
+                 "actors of type `%s' do not support height-for-width "
+                 "layouts.",
+                 g_type_name (G_OBJECT_TYPE (layout)));
+
+      if (height)
+        *height = -1;
+    }
+}
+
+/**
+ * clutter_layout_natural_request:
+ * @layout: a #ClutterLayout
+ * @width: return location for the natural width
+ * @height: return location for the natural height
+ *
+ * Queries a #ClutterLayout actor for its natural (default) width
+ * and height.
+ *
+ * Since: 0.4
+ */
+void
+clutter_layout_natural_request (ClutterLayout *layout,
+                                gint          *width,
+                                gint          *height)
+{
+  ClutterLayoutFlags layout_type;
+
+  g_return_if_fail (CLUTTER_IS_LAYOUT (layout));
+
+  layout_type = clutter_layout_get_layout_flags (layout);
+  if (layout_type & CLUTTER_LAYOUT_NATURAL)
+    {
+      ClutterUnit u_width, u_height;
+
+      CLUTTER_LAYOUT_GET_IFACE (layout)->natural_request (layout,
+                                                          &u_width,
+                                                          &u_height);
+    
+      if (width)
+        *width = CLUTTER_UNITS_TO_INT (u_width);
+
+      if (height)
+        *height = CLUTTER_UNITS_TO_INT (u_height);
+    }
+  else
+    {
+      g_warning ("Actor queried for natural size, but actors of type `%s' "
+                 "do not support natural-size layouts.",
+                 g_type_name (G_OBJECT_TYPE (layout)));
+
+      if (width)
+        *width = -1;
+      if (height)
+        *height = -1;
+    }
+}
+
+/**
+ * clutter_layout_tune_request:
+ * @layout: a #ClutterLayout
+ * @given_width: width allocated by the parent
+ * @given_height: height allocated by the parent
+ * @width: return location for the new width
+ * @height: return location for the new height
+ *
+ * Iteratively queries a #ClutterLayout actor until it finds
+ * its desired size, given a width and height tuple.
+ *
+ * Since: 0.4
+ */
+void
+clutter_layout_tune_request (ClutterLayout *layout,
+                             gint           given_width,
+                             gint           given_height,
+                             gint          *width,
+                             gint          *height)
+{
+  ClutterLayoutFlags layout_type;
+  gint tries;
+  ClutterUnit try_width, try_height;
+  ClutterUnit new_width, new_height;
+
+  g_return_if_fail (CLUTTER_IS_LAYOUT (layout));
+
+  layout_type = clutter_layout_get_layout_flags (layout);
+  if ((layout_type & CLUTTER_LAYOUT_TUNABLE) == 0)
+    {
+      g_warning ("Actor queried for tunable size size but actors of "
+                 "type `%s' do not support tunable layouts.",
+                 g_type_name (G_OBJECT_TYPE (layout)));
+      
+      if (width)
+        *width = -1;
+
+      if (height)
+        *height = -1;
+
+      return;
+    }
+
+  tries = 0;
+  try_width = CLUTTER_UNITS_FROM_INT (given_width);
+  try_height = CLUTTER_UNITS_FROM_INT (given_height);
+  new_width = new_height = 0;
+
+  do
+    {
+      gboolean res;
+
+      res = CLUTTER_LAYOUT_GET_IFACE (layout)->tune_request (layout,
+                                                             try_width,
+                                                             try_height,
+                                                             &new_width,
+                                                             &new_height);
+
+      if (res)
+        break;
+
+      if (new_width)
+        try_width = new_width;
+
+      if (new_height)
+        try_height = new_height;
+
+      new_width = new_height = 0;
+
+      tries += 1;
+    }
+  while (tries <= MAX_TUNE_REQUESTS);
+
+  if (width)
+    *width = CLUTTER_UNITS_TO_INT (new_width);
+
+  if (height)
+    *height = CLUTTER_UNITS_TO_INT (new_height);
+}
diff --git a/clutter/clutter-layout.h b/clutter/clutter-layout.h
new file mode 100644 (file)
index 0000000..de08eed
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * ClutterLayout: interface to be implemented by actors providing
+ *                extended layouts.
+ *
+ * Author: Emmanuele Bassi <ebassi@openedhand.com>
+ */
+
+#ifndef __CLUTTER_LAYOUT_H__
+#define __CLUTTER_LAYOUT_H__
+
+#include <clutter/clutter-actor.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_LAYOUT             (clutter_layout_get_type ())
+#define CLUTTER_LAYOUT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LAYOUT, ClutterLayout))
+#define CLUTTER_IS_LAYOUT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LAYOUT))
+#define CLUTTER_LAYOUT_GET_IFACE(obj)   (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_LAYOUT, ClutterLayoutIface))
+
+/**
+ * ClutterLayoutFlags
+ *
+ * Type of layouts supported by an actor.
+ *
+ * @CLUTTER_LAYOUT_NONE: No layout (default behaviour)
+ * @CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT: Width-for-height
+ * @CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH: Height-for-width
+ * @CLUTTER_LAYOUT_NATURAL: Natural size request
+ * @CLUTTER_LAYOUT_TUNABLE: Tunable size request
+ *
+ * Since: 0.4
+ */
+typedef enum {
+  CLUTTER_LAYOUT_NONE             = 0,
+  CLUTTER_LAYOUT_WIDTH_FOR_HEIGHT = 1 << 0,
+  CLUTTER_LAYOUT_HEIGHT_FOR_WIDTH = 1 << 1,
+  CLUTTER_LAYOUT_NATURAL          = 1 << 2,
+  CLUTTER_LAYOUT_TUNABLE          = 1 << 3
+} ClutterLayoutFlags;
+
+typedef struct _ClutterLayout           ClutterLayout; /* dummy */
+typedef struct _ClutterLayoutIface      ClutterLayoutIface;
+
+struct _ClutterLayoutIface
+{
+  GTypeInterface g_iface;
+
+  /* Retrieve the layout mode used by the actor */
+  ClutterLayoutFlags (* get_layout_flags) (ClutterLayout *layout);
+  
+  /* Width-for-Height and Height-for-Width: one size is known
+   * and the other is queried. useful for labels and unidirectional
+   * containers, like vertical and horizontal boxes.
+   */
+  void               (* width_for_height) (ClutterLayout *layout,
+                                           ClutterUnit   *width,
+                                           ClutterUnit    height);
+  void               (* height_for_width) (ClutterLayout *layout,
+                                           ClutterUnit    width,
+                                           ClutterUnit   *height);
+
+  /* Natural size request: the actor is queried for its natural
+   * size and the container can decide to either scale the actor
+   * or to resize itself to make it fit. useful for textures
+   * or shapes.
+   */
+  void               (* natural_request)  (ClutterLayout *layout,
+                                           ClutterUnit   *width,
+                                           ClutterUnit   *height);
+
+  /* Iterative allocation: the actor is iteratively queried
+   * for its size, until it finds it.
+   */
+  gboolean           (* tune_request)     (ClutterLayout *layout,
+                                           ClutterUnit    given_width,
+                                           ClutterUnit    given_height,
+                                           ClutterUnit   *width,
+                                           ClutterUnit   *height);
+
+  /* padding, for future expansion */
+  void (*_clutter_layout1) (void);
+  void (*_clutter_layout2) (void);
+  void (*_clutter_layout3) (void);
+  void (*_clutter_layout4) (void);
+  void (*_clutter_layout5) (void);
+  void (*_clutter_layout6) (void);
+  void (*_clutter_layout7) (void);
+  void (*_clutter_layout8) (void);
+};
+
+GType              clutter_layout_get_type         (void) G_GNUC_CONST;
+
+ClutterLayoutFlags clutter_layout_get_layout_flags (ClutterLayout *layout);
+void               clutter_layout_width_for_height (ClutterLayout *layout,
+                                                    gint          *width,
+                                                    gint           height);
+void               clutter_layout_height_for_width (ClutterLayout *layout,
+                                                    gint           width,
+                                                    gint          *height);
+void               clutter_layout_natural_request  (ClutterLayout *layout,
+                                                    gint          *width,
+                                                    gint          *height);
+void               clutter_layout_tune_request     (ClutterLayout *layout,
+                                                    gint           given_width,
+                                                    gint           given_height,
+                                                    gint          *width,
+                                                    gint          *height);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_LAYOUT_H__ */