$(srcdir)/clutter-colorize-effect.h \
$(srcdir)/clutter-constraint.h \
$(srcdir)/clutter-container.h \
+ $(srcdir)/clutter-content.h \
$(srcdir)/clutter-deform-effect.h \
$(srcdir)/clutter-deprecated.h \
$(srcdir)/clutter-desaturate-effect.h \
$(srcdir)/clutter-colorize-effect.c \
$(srcdir)/clutter-constraint.c \
$(srcdir)/clutter-container.c \
+ $(srcdir)/clutter-content.c \
$(srcdir)/clutter-deform-effect.c \
$(srcdir)/clutter-desaturate-effect.c \
$(srcdir)/clutter-device-manager.c \
$(srcdir)/clutter-actor-private.h \
$(srcdir)/clutter-backend-private.h \
$(srcdir)/clutter-bezier.h \
+ $(srcdir)/clutter-content-private.h \
$(srcdir)/clutter-debug.h \
$(srcdir)/clutter-device-manager-private.h \
$(srcdir)/clutter-easing.h \
#include "clutter-color.h"
#include "clutter-constraint.h"
#include "clutter-container.h"
+#include "clutter-content-private.h"
#include "clutter-debug.h"
#include "clutter-effect-private.h"
#include "clutter-enum-types.h"
/* delegate object used to allocate the children of this actor */
ClutterLayoutManager *layout_manager;
+ /* delegate object used to paint the contents of this actor */
+ ClutterContent *content;
+
+ ClutterContentGravity content_gravity;
+
/* used when painting, to update the paint volume */
ClutterEffect *current_effect;
PROP_FIRST_CHILD,
PROP_LAST_CHILD,
+ PROP_CONTENT,
+ PROP_CONTENT_GRAVITY,
+ PROP_CONTENT_BOX,
+
PROP_LAST
};
g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
+ /* if the allocation changes, so does the content box */
+ if (priv->content != NULL)
+ g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
+
retval = TRUE;
}
else
clutter_paint_node_unref (node);
}
+ if (priv->content != NULL)
+ _clutter_content_paint_content (priv->content, actor, root);
+
if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
clutter_actor_set_background_color (actor, g_value_get_boxed (value));
break;
+ case PROP_CONTENT:
+ clutter_actor_set_content (actor, g_value_get_object (value));
+ break;
+
+ case PROP_CONTENT_GRAVITY:
+ clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_set_object (value, priv->last_child);
break;
+ case PROP_CONTENT:
+ g_value_set_object (value, priv->content);
+ break;
+
+ case PROP_CONTENT_GRAVITY:
+ g_value_set_enum (value, priv->content_gravity);
+ break;
+
+ case PROP_CONTENT_BOX:
+ {
+ ClutterActorBox box = { 0, };
+
+ clutter_actor_get_content_box (actor, &box);
+ g_value_set_boxed (value, &box);
+ }
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
if (priv->layout_manager != NULL)
{
clutter_layout_manager_set_container (priv->layout_manager, NULL);
- g_object_unref (priv->layout_manager);
- priv->layout_manager = NULL;
+ g_clear_object (&priv->layout_manager);
+ }
+
+ if (priv->content != NULL)
+ {
+ _clutter_content_detached (priv->content, self);
+ g_clear_object (&priv->content);
}
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
CLUTTER_TYPE_ACTOR,
CLUTTER_PARAM_READABLE);
+ /**
+ * ClutterActor:content:
+ *
+ * The #ClutterContent implementation that controls the content
+ * of the actor.
+ *
+ * Since: 1.10
+ */
+ obj_props[PROP_CONTENT] =
+ g_param_spec_object ("content",
+ P_("Content"),
+ P_("Delegate object for painting the actor's content"),
+ CLUTTER_TYPE_CONTENT,
+ CLUTTER_PARAM_READWRITE);
+
+ /**
+ * ClutterActor:content-gravity:
+ *
+ * The alignment that should be honoured by the #ClutterContent
+ * set with the #ClutterActor:content property.
+ *
+ * Changing the value of this property will change the bounding box of
+ * the content; you can use the #ClutterActor:content-box property to
+ * get the position and size of the content within the actor's
+ * allocation.
+ *
+ * This property is meaningful only for #ClutterContent implementations
+ * that have a preferred size, and if the preferred size is smaller than
+ * the actor's allocation.
+ *
+ * Since: 1.10
+ */
+ obj_props[PROP_CONTENT_GRAVITY] =
+ g_param_spec_enum ("content-gravity",
+ P_("Content Gravity"),
+ P_("Alignment of the actor's content"),
+ CLUTTER_TYPE_CONTENT_GRAVITY,
+ CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
+ CLUTTER_PARAM_READWRITE);
+
+ /**
+ * ClutterActor:content-box:
+ *
+ * The bounding box for the #ClutterContent used by the actor.
+ *
+ * The value of this property is controlled by the #ClutterActor:allocation
+ * and #ClutterActor:content-gravity properties of #ClutterActor.
+ *
+ * The bounding box for the content is guaranteed to never exceed the
+ * allocation's of the actor.
+ *
+ * Since: 1.10
+ */
+ obj_props[PROP_CONTENT_BOX] =
+ g_param_spec_boxed ("content-box",
+ P_("Content Box"),
+ P_("The bounding box of the actor's content"),
+ CLUTTER_TYPE_ACTOR_BOX,
+ CLUTTER_PARAM_READABLE);
+
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
/**
priv->last_paint_volume_valid = TRUE;
priv->transform_valid = FALSE;
+
+ /* the default is to stretch the content, to match the
+ * current behaviour of basically all actors. also, it's
+ * the easiest thing to compute.
+ */
+ priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
}
/**
g_array_remove_index (info->states, info->states->len - 1);
info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
}
+
+/**
+ * clutter_actor_set_content:
+ * @self: a #ClutterActor
+ * @content: (allow-none): a #ClutterContent, or %NULL
+ *
+ * Sets the contents of a #ClutterActor.
+ *
+ * Since: 1.10
+ */
+void
+clutter_actor_set_content (ClutterActor *self,
+ ClutterContent *content)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
+
+ priv = self->priv;
+
+ if (priv->content != NULL)
+ {
+ _clutter_content_detached (priv->content, self);
+ g_object_unref (priv->content);
+ }
+
+ priv->content = content;
+
+ if (priv->content != NULL)
+ {
+ g_object_ref (priv->content);
+ _clutter_content_attached (priv->content, self);
+ }
+
+ /* given that the content is always painted within the allocation,
+ * we only need to queue a redraw here
+ */
+ clutter_actor_queue_redraw (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
+
+ /* if the content gravity is not resize-fill, and the new content has a
+ * different preferred size than the previous one, then the content box
+ * may have been changed. since we compute that lazily, we just notify
+ * here, and let whomever watches :content-box do whatever they need to
+ * do.
+ */
+ if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
+}
+
+/**
+ * clutter_actor_get_content:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the contents of @self.
+ *
+ * Return value: (transfer none): a pointer to the #ClutterContent instance,
+ * or %NULL if none was set
+ *
+ * Since: 1.10
+ */
+ClutterContent *
+clutter_actor_get_content (ClutterActor *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+ return self->priv->content;
+}
+
+/**
+ * clutter_actor_set_content_gravity:
+ * @self: a #ClutterActor
+ * @gravity: the #ClutterContentGravity
+ *
+ * Sets the gravity of the #ClutterContent used by @self.
+ *
+ * See the description of the #ClutterActor:content-gravity property for
+ * more information.
+ *
+ * Since: 1.10
+ */
+void
+clutter_actor_set_content_gravity (ClutterActor *self,
+ ClutterContentGravity gravity)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ priv = self->priv;
+
+ if (priv->content_gravity == gravity)
+ return;
+
+ priv->content_gravity = gravity;
+
+ clutter_actor_queue_redraw (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
+}
+
+/**
+ * clutter_actor_get_content_gravity:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the content gravity as set using
+ * clutter_actor_get_content_gravity().
+ *
+ * Return value: the content gravity
+ *
+ * Since: 1.10
+ */
+ClutterContentGravity
+clutter_actor_get_content_gravity (ClutterActor *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
+ CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
+
+ return self->priv->content_gravity;
+}
+
+/**
+ * clutter_actor_get_content_box:
+ * @self: a #ClutterActor
+ * @box: (out caller-allocates): the return location for the bounding
+ * box for the #ClutterContent
+ *
+ * Retrieves the bounding box for the #ClutterContent of @self.
+ *
+ * If no #ClutterContent is set for @self, or if @self has not been
+ * allocated yet, then the result is undefined.
+ *
+ * The content box is guaranteed to be, at most, as big as the allocation
+ * of the #ClutterActor.
+ *
+ * If the #ClutterContent used by the actor has a preferred size, then
+ * it is possible to modify the content box by using the
+ * #ClutterActor:content-gravity property.
+ *
+ * Since: 1.10
+ */
+void
+clutter_actor_get_content_box (ClutterActor *self,
+ ClutterActorBox *box)
+{
+ ClutterActorPrivate *priv;
+ gfloat content_w, content_h;
+ gfloat alloc_w, alloc_h;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (box != NULL);
+
+ priv = self->priv;
+
+ if (!clutter_actor_has_allocation (self))
+ return;
+
+ if (priv->content == NULL)
+ return;
+
+ *box = priv->allocation;
+
+ /* no need to do any more work */
+ if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
+ return;
+
+ /* if the content does not have a preferred size then there is
+ * no point in computing the content box
+ */
+ if (!_clutter_content_get_preferred_size (priv->content,
+ &content_w,
+ &content_h))
+ return;
+
+ clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
+
+ switch (priv->content_gravity)
+ {
+ case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
+ box->x2 = box->x1 + MIN (content_w, alloc_w);
+ box->y2 = box->y1 + MIN (content_h, alloc_h);
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_TOP:
+ if (alloc_w > content_w)
+ {
+ box->x1 += ceilf ((alloc_w - content_w) / 2.0);
+ box->x2 = box->x1 + content_w;
+ }
+ box->y2 = box->y1 + MIN (content_h, alloc_h);
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
+ if (alloc_w > content_w)
+ {
+ box->x1 += (alloc_w - content_w);
+ box->x2 = box->x1 + content_w;
+ }
+ box->y2 = box->y1 + MIN (content_h, alloc_h);
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_LEFT:
+ box->x2 = box->x1 + MIN (content_w, alloc_w);
+ if (alloc_h > content_h)
+ {
+ box->y1 += ceilf ((alloc_h - content_h) / 2.0);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_CENTER:
+ if (alloc_w > content_w)
+ {
+ box->x1 += ceilf ((alloc_w - content_w) / 2.0);
+ box->x2 = box->x1 + content_w;
+ }
+ if (alloc_h > content_h)
+ {
+ box->y1 += ceilf ((alloc_h - content_h) / 2.0);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_RIGHT:
+ if (alloc_w > content_w)
+ {
+ box->x1 += (alloc_w - content_w);
+ box->x2 = box->x1 + content_w;
+ }
+ if (alloc_h > content_h)
+ {
+ box->y1 += ceilf ((alloc_h - content_h) / 2.0);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
+ box->x2 = box->x1 + MIN (content_w, alloc_w);
+ if (alloc_h > content_h)
+ {
+ box->y1 += (alloc_h - content_h);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_BOTTOM:
+ if (alloc_w > content_w)
+ {
+ box->x1 += ceilf ((alloc_w - content_w) / 2.0);
+ box->x2 = box->x1 + content_w;
+ }
+ if (alloc_h > content_h)
+ {
+ box->y1 += (alloc_h - content_h);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
+ if (alloc_w > content_w)
+ {
+ box->x1 += (alloc_w - content_w);
+ box->x2 = box->x1 + content_w;
+ }
+ if (alloc_h > content_h)
+ {
+ box->y1 += (alloc_h - content_h);
+ box->y2 = box->y1 + content_h;
+ }
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
+ g_assert_not_reached ();
+ break;
+
+ case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
+ if (content_w >= content_h && content_h > 0)
+ {
+ double ratio = content_w / content_h;
+
+ box->x2 = box->x1 + alloc_w;
+
+ box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
+ box->y2 = box->y1 + (alloc_h / ratio);
+ }
+ else if (content_h > content_w && content_w > 0)
+ {
+ double ratio = content_h / content_w;
+
+ box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
+ box->x2 = box->x2 + (alloc_w / ratio);
+
+ box->y2 = box->x1 + alloc_h;
+ }
+ break;
+ }
+}
gboolean clutter_actor_get_paint_box (ClutterActor *self,
ClutterActorBox *box);
gboolean clutter_actor_has_overlaps (ClutterActor *self);
+
+/* Content */
+CLUTTER_AVAILABLE_IN_1_10
+void clutter_actor_set_content (ClutterActor *self,
+ ClutterContent *content);
+CLUTTER_AVAILABLE_IN_1_10
+ClutterContent * clutter_actor_get_content (ClutterActor *self);
+CLUTTER_AVAILABLE_IN_1_10
+void clutter_actor_set_content_gravity (ClutterActor *self,
+ ClutterContentGravity gravity);
+CLUTTER_AVAILABLE_IN_1_10
+ClutterContentGravity clutter_actor_get_content_gravity (ClutterActor *self);
+CLUTTER_AVAILABLE_IN_1_10
+void clutter_actor_get_content_box (ClutterActor *self,
+ ClutterActorBox *box);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_set_background_color (ClutterActor *self,
const ClutterColor *color);
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifndef __CLUTTER_CONTENT_PRIVATE_H__
+#define __CLUTTER_CONTENT_PRIVATE_H__
+
+#include <clutter/clutter-content.h>
+
+G_BEGIN_DECLS
+
+gboolean _clutter_content_get_preferred_size (ClutterContent *content,
+ gfloat *width,
+ gfloat *height);
+
+void _clutter_content_attached (ClutterContent *content,
+ ClutterActor *actor);
+void _clutter_content_detached (ClutterContent *content,
+ ClutterActor *actor);
+
+void _clutter_content_paint_content (ClutterContent *content,
+ ClutterActor *actor,
+ ClutterPaintNode *node);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_CONTENT_PRIVATE_H__ */
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+/**
+ * SECTION:clutter-content
+ * @Title: ClutterContent
+ * @short_desc: Delegate for painting the content of an actor
+ *
+ * #ClutterContent is an interface to implement types responsible for
+ * painting the content of a #ClutterActor.
+ *
+ * Multiple actors can use the same #ClutterContent instance, in order
+ * to share the resources associated with painting the same content.
+ *
+ * #ClutterContent is available since Clutter 1.10.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-content-private.h"
+
+#include "clutter-debug.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+
+typedef struct _ClutterContentIface ClutterContentInterface;
+
+static GQuark quark_content_actors = 0;
+
+G_DEFINE_INTERFACE (ClutterContent, clutter_content, G_TYPE_OBJECT)
+
+static gboolean
+clutter_content_real_get_preferred_size (ClutterContent *content,
+ gfloat *width,
+ gfloat *height)
+{
+ if (width != NULL)
+ *width = 0.f;
+
+ if (height != NULL)
+ *height = 0.f;
+
+ return FALSE;
+}
+
+static void
+clutter_content_real_attached (ClutterContent *content,
+ ClutterActor *actor)
+{
+ GObject *obj = G_OBJECT (content);
+ GHashTable *actors;
+
+ actors = g_object_get_qdata (obj, quark_content_actors);
+ if (actors == NULL)
+ {
+ actors = g_hash_table_new (NULL, NULL);
+ g_object_set_qdata_full (obj, quark_content_actors,
+ actors,
+ (GDestroyNotify) g_hash_table_unref);
+ }
+
+ g_hash_table_insert (actors, actor, actor);
+}
+
+static void
+clutter_content_real_detached (ClutterContent *content,
+ ClutterActor *actor)
+{
+ GObject *obj = G_OBJECT (content);
+ GHashTable *actors;
+
+ actors = g_object_get_qdata (obj, quark_content_actors);
+ g_assert (actors != NULL);
+
+ g_hash_table_remove (actors, actor);
+
+ if (g_hash_table_size (actors) == 0)
+ g_object_set_qdata (obj, quark_content_actors, NULL);
+}
+
+static void
+clutter_content_real_invalidate (ClutterContent *content)
+{
+ GHashTable *actors;
+ GHashTableIter iter;
+ gpointer key_p, value_p;
+
+ actors = g_object_get_qdata (G_OBJECT (content), quark_content_actors);
+ if (actors == NULL)
+ return;
+
+ g_hash_table_iter_init (&iter, actors);
+ while (g_hash_table_iter_next (&iter, &key_p, &value_p))
+ {
+ ClutterActor *actor = key_p;
+
+ g_assert (actor != NULL);
+
+ clutter_actor_queue_redraw (actor);
+ }
+}
+
+static void
+clutter_content_real_paint_content (ClutterContent *content,
+ ClutterActor *actor,
+ ClutterPaintNode *context)
+{
+}
+
+static void
+clutter_content_default_init (ClutterContentInterface *iface)
+{
+ quark_content_actors = g_quark_from_static_string ("-clutter-content-actors");
+
+ iface->get_preferred_size = clutter_content_real_get_preferred_size;
+ iface->paint_content = clutter_content_real_paint_content;
+ iface->attached = clutter_content_real_attached;
+ iface->detached = clutter_content_real_detached;
+ iface->invalidate = clutter_content_real_invalidate;
+}
+
+/**
+ * clutter_content_invalidate:
+ * @content: a #ClutterContent
+ *
+ * Invalidates a #ClutterContent.
+ *
+ * This function should be called by #ClutterContent implementations when
+ * they change the way a the content should be painted regardless of the
+ * actor state.
+ *
+ * Since: 1.10
+ */
+void
+clutter_content_invalidate (ClutterContent *content)
+{
+ g_return_if_fail (CLUTTER_IS_CONTENT (content));
+
+ CLUTTER_CONTENT_GET_IFACE (content)->invalidate (content);
+}
+
+/*< private >
+ * _clutter_content_attached:
+ * @content: a #ClutterContent
+ * @actor: a #ClutterActor
+ *
+ * Attaches @actor to the @content.
+ *
+ * This function should be used internally every time a #ClutterActor
+ * is associated to a #ClutterContent, to set up a backpointer from
+ * the @content to the @actor.
+ *
+ * This function will invoke the #ClutterContentIface.attached() virtual
+ * function.
+ */
+void
+_clutter_content_attached (ClutterContent *content,
+ ClutterActor *actor)
+{
+ CLUTTER_CONTENT_GET_IFACE (content)->attached (content, actor);
+}
+
+/*< private >
+ * _clutter_content_detached:
+ * @content: a #ClutterContent
+ * @actor: a #ClutterActor
+ *
+ * Detaches @actor from @content.
+ *
+ * This function should be used internally every time a #ClutterActor
+ * removes the association with a #ClutterContent.
+ *
+ * This function will invoke the #ClutterContentIface.detached() virtual
+ * function.
+ */
+void
+_clutter_content_detached (ClutterContent *content,
+ ClutterActor *actor)
+{
+ CLUTTER_CONTENT_GET_IFACE (content)->detached (content, actor);
+}
+
+/*< private >
+ * _clutter_content_paint_content:
+ * @content: a #ClutterContent
+ * @actor: a #ClutterActor
+ * @context: a #ClutterPaintNode
+ *
+ * Creates the render tree for the @content and @actor.
+ *
+ * This function will invoke the #ClutterContentIface.paint_content()
+ * virtual function.
+ */
+void
+_clutter_content_paint_content (ClutterContent *content,
+ ClutterActor *actor,
+ ClutterPaintNode *node)
+{
+ CLUTTER_CONTENT_GET_IFACE (content)->paint_content (content, actor, node);
+}
+
+/*< private >
+ * _clutter_content_get_preferred_size:
+ * @content: a #ClutterContent
+ * @width: (out): return location for the natural width of the content
+ * @height: (out): return location for the natural height of the content
+ *
+ * Retrieves the natural size of the @content, if any.
+ *
+ * The natural size of a #ClutterContent is defined as the size the content
+ * would have regardless of the allocation of the actor that is painting it,
+ * for instance the size of an image data.
+ *
+ * Return value: %TRUE if the content has a preferred size, and %FALSE
+ * otherwise
+ */
+gboolean
+_clutter_content_get_preferred_size (ClutterContent *content,
+ gfloat *width,
+ gfloat *height)
+{
+ return CLUTTER_CONTENT_GET_IFACE (content)->get_preferred_size (content,
+ width,
+ height);
+}
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_CONTENT_H__
+#define __CLUTTER_CONTENT_H__
+
+#include <clutter/clutter-types.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_CONTENT (clutter_content_get_type ())
+#define CLUTTER_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONTENT, ClutterContent))
+#define CLUTTER_IS_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONTENT))
+#define CLUTTER_CONTENT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_CONTENT, ClutterContentIface))
+
+typedef struct _ClutterContentIface ClutterContentIface;
+
+/**
+ * ClutterContent:
+ *
+ * The <structname>ClutterContent</structname> structure is an opaque type
+ * whose members cannot be acccessed directly.
+ *
+ * Since: 1.10
+ */
+
+/**
+ * ClutterContentIface:
+ * @get_preferred_size: virtual function; should be overridden by subclasses
+ * of #ClutterContent that have a natural size
+ * @paint_content: virtual function; called each time the content needs to
+ * paint itself
+ * @attached: virtual function; called each time a #ClutterContent is attached
+ * to a #ClutterActor. If overridden, the subclass must chain up to the
+ * parent class implementation.
+ * @detached: virtual function; called each time a #ClutterContent is detached
+ * from a #ClutterActor. If overridden, the subclass must chain up to the
+ * parent class implementation.
+ * @invalidate: virtual function; called each time a #ClutterContent state
+ * is changed. If overridden, the subclass must chain up to the parent
+ * class implementation.
+ *
+ * The <structname>ClutterContentIface</structname> structure contains only
+ * private data.
+ *
+ * Since: 1.10
+ */
+struct _ClutterContentIface
+{
+ /*< private >*/
+ GTypeInterface g_iface;
+
+ /*< public >*/
+ gboolean (* get_preferred_size) (ClutterContent *content,
+ gfloat *width,
+ gfloat *height);
+ void (* paint_content) (ClutterContent *content,
+ ClutterActor *actor,
+ ClutterPaintNode *node);
+
+ void (* attached) (ClutterContent *content,
+ ClutterActor *actor);
+ void (* detached) (ClutterContent *content,
+ ClutterActor *actor);
+
+ void (* invalidate) (ClutterContent *content);
+};
+
+GType clutter_content_get_type (void) G_GNUC_CONST;
+
+void clutter_content_invalidate (ClutterContent *content);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_CONTENT_H__ */
CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2
} ClutterRepaintFlags;
+/**
+ * ClutterContentGravity:
+ * @CLUTTER_CONTENT_GRAVITY_TOP_LEFT: Align the content to the top left corner
+ * @CLUTTER_CONTENT_GRAVITY_TOP: Align the content to the top edge
+ * @CLUTTER_CONTENT_GRAVITY_TOP_RIGHT: Align the content to the top right corner
+ * @CLUTTER_CONTENT_GRAVITY_LEFT: Align the content to the left edge
+ * @CLUTTER_CONTENT_GRAVITY_CENTER: Align the content to the center
+ * @CLUTTER_CONTENT_GRAVITY_RIGHT: Align the content to the right edge
+ * @CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT: Align the content to the bottom left corner
+ * @CLUTTER_CONTENT_GRAVITY_BOTTOM: Align the content to the bottom edge
+ * @CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT: Align the content to the bottom right corner
+ * @CLUTTER_CONTENT_GRAVITY_RESIZE_FILL: Resize the content to fill the allocation
+ * @CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT: Resize the content to remain within the
+ * allocation, while maintaining the aspect ratio
+ *
+ * Controls the alignment of the #ClutterContent inside a #ClutterActor.
+ *
+ * Since: 1.10
+ */
+typedef enum {
+ CLUTTER_CONTENT_GRAVITY_TOP_LEFT,
+ CLUTTER_CONTENT_GRAVITY_TOP,
+ CLUTTER_CONTENT_GRAVITY_TOP_RIGHT,
+
+ CLUTTER_CONTENT_GRAVITY_LEFT,
+ CLUTTER_CONTENT_GRAVITY_CENTER,
+ CLUTTER_CONTENT_GRAVITY_RIGHT,
+
+ CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT,
+ CLUTTER_CONTENT_GRAVITY_BOTTOM,
+ CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT,
+
+ CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
+ CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT
+} ClutterContentGravity;
+
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */
typedef struct _ClutterLayoutManager ClutterLayoutManager;
typedef struct _ClutterActorIter ClutterActorIter;
typedef struct _ClutterPaintNode ClutterPaintNode;
+typedef struct _ClutterContent ClutterContent; /* dummy */
typedef struct _ClutterAlpha ClutterAlpha;
typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */
#include "clutter-colorize-effect.h"
#include "clutter-constraint.h"
#include "clutter-container.h"
+#include "clutter-content.h"
#include "clutter-deform-effect.h"
#include "clutter-desaturate-effect.h"
#include "clutter-device-manager.h"
test-drop.c \
test-devices.c \
test-actor.c \
- test-transitions.c
+ test-transitions.c \
+ test-content.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c
--- /dev/null
+#include <stdlib.h>
+#include <gmodule.h>
+#include <clutter/clutter.h>
+
+typedef struct _ColorContent {
+ GObject parent_instance;
+
+ double red;
+ double green;
+ double blue;
+ double alpha;
+
+ float padding;
+} ColorContent;
+
+typedef struct _ColorContentClass {
+ GObjectClass parent_class;
+} ColorContentClass;
+
+static void clutter_content_iface_init (ClutterContentIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ColorContent, color_content, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
+ clutter_content_iface_init))
+
+static void
+color_content_paint_content (ClutterContent *content,
+ ClutterActor *actor,
+ ClutterPaintNode *root)
+{
+ ColorContent *self = (ColorContent *) content;
+ ClutterActorBox box, content_box;
+ ClutterColor color;
+ PangoLayout *layout;
+ PangoRectangle logical;
+ ClutterPaintNode *node;
+
+#if 0
+ g_debug ("Painting content [%p] "
+ "{ r:%.2f, g:%.2f, b:%.2f, a:%.2f } "
+ "for actor [%p] (context: [%p])",
+ content,
+ self->red,
+ self->green,
+ self->blue,
+ self->alpha,
+ actor, context);
+#endif
+
+ clutter_actor_get_content_box (actor, &content_box);
+
+ box = content_box;
+ box.x1 += self->padding;
+ box.y1 += self->padding;
+ box.x2 -= self->padding;
+ box.y2 -= self->padding;
+
+ color.alpha = self->alpha * 255;
+
+ color.red = self->red * 255;
+ color.green = self->green * 255;
+ color.blue = self->blue * 255;
+
+ node = clutter_color_node_new (&color);
+ clutter_paint_node_add_rectangle (node, &box);
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
+
+ color.red = (1.0 - self->red) * 255;
+ color.green = (1.0 - self->green) * 255;
+ color.blue = (1.0 - self->blue) * 255;
+
+ layout = clutter_actor_create_pango_layout (actor, "A");
+ pango_layout_get_pixel_extents (layout, NULL, &logical);
+
+ node = clutter_text_node_new (layout, &color);
+
+ /* top-left */
+ box.x1 = clutter_actor_box_get_x (&content_box);
+ box.y1 = clutter_actor_box_get_y (&content_box);
+ clutter_paint_node_add_rectangle (node, &box);
+
+ /* top-right */
+ box.x1 = clutter_actor_box_get_x (&content_box)
+ + clutter_actor_box_get_width (&content_box)
+ - logical.width;
+ box.y1 = clutter_actor_box_get_y (&content_box);
+ clutter_paint_node_add_rectangle (node, &box);
+
+ /* bottom-right */
+ box.x1 = clutter_actor_box_get_x (&content_box)
+ + clutter_actor_box_get_width (&content_box)
+ - logical.width;
+ box.y1 = clutter_actor_box_get_y (&content_box)
+ + clutter_actor_box_get_height (&content_box)
+ - logical.height;
+ clutter_paint_node_add_rectangle (node, &box);
+
+ /* bottom-left */
+ box.x1 = clutter_actor_box_get_x (&content_box);
+ box.y1 = clutter_actor_box_get_y (&content_box)
+ + clutter_actor_box_get_height (&content_box)
+ - logical.height;
+ clutter_paint_node_add_rectangle (node, &box);
+
+ /* center */
+ box.x1 = clutter_actor_box_get_x (&content_box)
+ + (clutter_actor_box_get_width (&content_box) - logical.width) / 2.0;
+ box.y1 = clutter_actor_box_get_y (&content_box)
+ + (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0;
+ clutter_paint_node_add_rectangle (node, &box);
+
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
+
+ g_object_unref (layout);
+}
+
+static void
+clutter_content_iface_init (ClutterContentIface *iface)
+{
+ iface->paint_content = color_content_paint_content;
+}
+
+static void
+color_content_class_init (ColorContentClass *klass)
+{
+}
+
+static void
+color_content_init (ColorContent *self)
+{
+}
+
+static ClutterContent *
+color_content_new (double red,
+ double green,
+ double blue,
+ double alpha,
+ float padding)
+{
+ ColorContent *self = g_object_new (color_content_get_type (), NULL);
+
+ self->red = red;
+ self->green = green;
+ self->blue = blue;
+ self->alpha = alpha;
+ self->padding = padding;
+
+ return (ClutterContent *) self;
+}
+
+G_MODULE_EXPORT int
+test_content_main (int argc, char *argv[])
+{
+ ClutterActor *stage, *grid;
+ ClutterContent *content;
+ int i, n_rects;
+
+ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ stage = clutter_stage_new ();
+ clutter_actor_set_name (stage, "Stage");
+ clutter_stage_set_title (CLUTTER_STAGE (stage), "Content");
+ clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+ clutter_actor_show (stage);
+
+ grid = clutter_actor_new ();
+ clutter_actor_set_name (grid, "Grid");
+ clutter_actor_set_margin_top (grid, 12);
+ clutter_actor_set_margin_right (grid, 12);
+ clutter_actor_set_margin_bottom (grid, 12);
+ clutter_actor_set_margin_left (grid, 12);
+ clutter_actor_set_layout_manager (grid, clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL));
+ clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
+ clutter_actor_add_child (stage, grid);
+
+ content = color_content_new (g_random_double_range (0.0, 1.0),
+ g_random_double_range (0.0, 1.0),
+ g_random_double_range (0.0, 1.0),
+ 1.0,
+ 2.0);
+
+ n_rects = g_random_int_range (12, 24);
+ for (i = 0; i < n_rects; i++)
+ {
+ ClutterActor *box = clutter_actor_new ();
+ ClutterColor bg_color = {
+ g_random_int_range (0, 255),
+ g_random_int_range (0, 255),
+ g_random_int_range (0, 255),
+ 255
+ };
+ char *name, *color;
+
+ color = clutter_color_to_string (&bg_color);
+ name = g_strconcat ("Box <", color, ">", NULL);
+ clutter_actor_set_name (box, name);
+
+ g_free (name);
+ g_free (color);
+
+ clutter_actor_set_background_color (box, &bg_color);
+ clutter_actor_set_content (box, content);
+ clutter_actor_set_size (box, 64, 64);
+
+ clutter_actor_add_child (grid, box);
+ }
+
+ clutter_main ();
+
+ g_object_unref (content);
+
+ return EXIT_SUCCESS;
+}
+
+G_MODULE_EXPORT const char *
+test_content_describe (void)
+{
+ return "A simple test for ClutterContent";
+}