diff --git a/.gitignore b/.gitignore
index 65a694870..9381cacfe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -149,6 +149,8 @@ TAGS
/tests/interactive/stamp-test-interactive
/tests/interactive/test-animator
/tests/interactive/test-stage-sizing
+/tests/interactive/test-drag
+/tests/interactive/test-constraints
/tests/conform/stamp-test-conformance
/tests/conform/test-anchors
/tests/conform/test-cogl-backface-culling
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 71ab39271..6b112e4d0 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -65,7 +65,10 @@ AM_CFLAGS = $(CLUTTER_CFLAGS) $(MAINTAINER_CFLAGS) $(GCOV_CFLAGS)
# please, keep this sorted alphabetically
source_h = \
+ $(srcdir)/clutter-action.h \
+ $(srcdir)/clutter-actor-meta.h \
$(srcdir)/clutter-actor.h \
+ $(srcdir)/clutter-align-constraint.h \
$(srcdir)/clutter-alpha.h \
$(srcdir)/clutter-animatable.h \
$(srcdir)/clutter-animation.h \
@@ -78,6 +81,7 @@ source_h = \
$(srcdir)/clutter-behaviour-path.h \
$(srcdir)/clutter-behaviour-rotate.h \
$(srcdir)/clutter-behaviour-scale.h \
+ $(srcdir)/clutter-bind-constraint.h \
$(srcdir)/clutter-binding-pool.h \
$(srcdir)/clutter-bin-layout.h \
$(srcdir)/clutter-box.h \
@@ -86,9 +90,11 @@ source_h = \
$(srcdir)/clutter-child-meta.h \
$(srcdir)/clutter-clone.h \
$(srcdir)/clutter-color.h \
+ $(srcdir)/clutter-constraint.h \
$(srcdir)/clutter-container.h \
$(srcdir)/clutter-deprecated.h \
$(srcdir)/clutter-device-manager.h \
+ $(srcdir)/clutter-drag-action.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-feature.h \
$(srcdir)/clutter-fixed.h \
@@ -138,7 +144,10 @@ include $(top_srcdir)/build/autotools/Makefile.am.enums
# please, keep this sorted alphabetically
source_c = \
+ $(srcdir)/clutter-action.c \
+ $(srcdir)/clutter-actor-meta.c \
$(srcdir)/clutter-actor.c \
+ $(srcdir)/clutter-align-constraint.c \
$(srcdir)/clutter-alpha.c \
$(srcdir)/clutter-animatable.c \
$(srcdir)/clutter-animation.c \
@@ -152,6 +161,7 @@ source_c = \
$(srcdir)/clutter-behaviour-rotate.c \
$(srcdir)/clutter-behaviour-scale.c \
$(srcdir)/clutter-bezier.c \
+ $(srcdir)/clutter-bind-constraint.c \
$(srcdir)/clutter-binding-pool.c \
$(srcdir)/clutter-bin-layout.c \
$(srcdir)/clutter-box.c \
@@ -160,8 +170,10 @@ source_c = \
$(srcdir)/clutter-child-meta.c \
$(srcdir)/clutter-clone.c \
$(srcdir)/clutter-color.c \
+ $(srcdir)/clutter-constraint.c \
$(srcdir)/clutter-container.c \
$(srcdir)/clutter-device-manager.c \
+ $(srcdir)/clutter-drag-action.c \
clutter-enum-types.c \
$(srcdir)/clutter-event.c \
$(srcdir)/clutter-feature.c \
@@ -206,6 +218,7 @@ source_c_priv = \
$(NULL)
source_h_priv = \
+ $(srcdir)/clutter-actor-meta-private.h \
$(srcdir)/clutter-bezier.h \
$(srcdir)/clutter-debug.h \
$(srcdir)/clutter-keysyms-table.h \
diff --git a/clutter/clutter-action.c b/clutter/clutter-action.c
new file mode 100644
index 000000000..636ab67ed
--- /dev/null
+++ b/clutter/clutter-action.c
@@ -0,0 +1,61 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+/**
+ * SECTION:clutter-action
+ * @Title: ClutterAction
+ * @Short_Description: Abstract class for actor actions
+ * @See_Also: #ClutterEffect
+ *
+ * #ClutterAction is an abstract base class for action that modify the
+ * user interaction of a #ClutterActor, just like #ClutterEffect is an
+ * abstract class for modifiers of the appearance of a #ClutterActor.
+ *
+ * Implementations of #ClutterAction are associated to an actor and can
+ * provide behavioral changes when dealing with user input - for instance
+ * drag and drop capabilities, or scrolling, or panning.
+ *
+ * #ClutterAction is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-action.h"
+
+#include "clutter-debug.h"
+#include "clutter-private.h"
+
+G_DEFINE_ABSTRACT_TYPE (ClutterAction, clutter_action, CLUTTER_TYPE_ACTOR_META);
+
+static void
+clutter_action_class_init (ClutterActionClass *klass)
+{
+}
+
+static void
+clutter_action_init (ClutterAction *self)
+{
+}
diff --git a/clutter/clutter-action.h b/clutter/clutter-action.h
new file mode 100644
index 000000000..afeafd91c
--- /dev/null
+++ b/clutter/clutter-action.h
@@ -0,0 +1,101 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_ACTION_H__
+#define __CLUTTER_ACTION_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_ACTION (clutter_action_get_type ())
+#define CLUTTER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTION, ClutterAction))
+#define CLUTTER_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTION))
+#define CLUTTER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTION, ClutterActionClass))
+#define CLUTTER_IS_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTION))
+#define CLUTTER_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTION, ClutterActionClass))
+
+typedef struct _ClutterActionClass ClutterActionClass;
+
+/**
+ * ClutterAction:
+ *
+ * The ClutterAction structure contains only
+ * private data and should be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterAction
+{
+ /*< private >*/
+ ClutterActorMeta parent_instance;
+};
+
+/**
+ * ClutterActionClass:
+ *
+ * The ClutterActionClass structure contains
+ * only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterActionClass
+{
+ /*< private >*/
+ ClutterActorMetaClass parent_class;
+
+ void (* _clutter_action1) (void);
+ void (* _clutter_action2) (void);
+ void (* _clutter_action3) (void);
+ void (* _clutter_action4) (void);
+ void (* _clutter_action5) (void);
+ void (* _clutter_action6) (void);
+ void (* _clutter_action7) (void);
+ void (* _clutter_action8) (void);
+};
+
+GType clutter_action_get_type (void) G_GNUC_CONST;
+
+/* ClutterActor API */
+void clutter_actor_add_action (ClutterActor *self,
+ ClutterAction *action);
+void clutter_actor_add_action_with_name (ClutterActor *self,
+ const gchar *name,
+ ClutterAction *action);
+void clutter_actor_remove_action (ClutterActor *self,
+ ClutterAction *action);
+void clutter_actor_remove_action_by_name (ClutterActor *self,
+ const gchar *name);
+ClutterAction *clutter_actor_get_action (ClutterActor *self,
+ const gchar *name);
+GList * clutter_actor_get_actions (ClutterActor *self);
+void clutter_actor_clear_actions (ClutterActor *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_ACTION_H__ */
diff --git a/clutter/clutter-actor-meta-private.h b/clutter/clutter-actor-meta-private.h
new file mode 100644
index 000000000..e880d025f
--- /dev/null
+++ b/clutter/clutter-actor-meta-private.h
@@ -0,0 +1,42 @@
+#ifndef __CLUTTER_ACTOR_META_PRIVATE_H__
+#define __CLUTTER_ACTOR_META_PRIVATE_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_META_GROUP (_clutter_meta_group_get_type ())
+#define CLUTTER_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_META_GROUP, ClutterMetaGroup))
+#define CLUTTER_IS_META_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_META_GROUP))
+
+typedef struct _ClutterMetaGroup ClutterMetaGroup;
+typedef struct _ClutterMetaGroupClass ClutterMetaGroupClass;
+
+struct _ClutterMetaGroup
+{
+ GObject parent_instance;
+
+ ClutterActor *actor;
+
+ GList *meta;
+};
+
+struct _ClutterMetaGroupClass
+{
+ GObjectClass parent_class;
+};
+
+GType _clutter_meta_group_get_type (void) G_GNUC_CONST;
+
+void _clutter_meta_group_add_meta (ClutterMetaGroup *group,
+ ClutterActorMeta *meta);
+void _clutter_meta_group_remove_meta (ClutterMetaGroup *group,
+ ClutterActorMeta *meta);
+G_CONST_RETURN GList *_clutter_meta_group_peek_metas (ClutterMetaGroup *group);
+void _clutter_meta_group_clear_metas (ClutterMetaGroup *group);
+ClutterActorMeta * _clutter_meta_group_get_meta (ClutterMetaGroup *group,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_ACTOR_META_PRIVATE_H__ */
diff --git a/clutter/clutter-actor-meta.c b/clutter/clutter-actor-meta.c
new file mode 100644
index 000000000..e318b8f86
--- /dev/null
+++ b/clutter/clutter-actor-meta.c
@@ -0,0 +1,457 @@
+/**
+ * SECTION:clutter-actor-meta
+ * @Title: ClutterActorMeta
+ * @Short_Description: Base class of actor modifiers
+ *
+ * #ClutterActorMeta is an abstract class providing a common API for
+ * modifiers of #ClutterActor
+ *
+ * A #ClutterActorMeta can only be owned by a single #ClutterActor at
+ * any time
+ *
+ * #ClutterActorMeta is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-actor-meta-private.h"
+
+#include "clutter-debug.h"
+#include "clutter-private.h"
+
+struct _ClutterActorMetaPrivate
+{
+ ClutterActor *actor;
+
+ gchar *name;
+
+ guint is_enabled : 1;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_ACTOR,
+ PROP_NAME,
+ PROP_ENABLED
+};
+
+G_DEFINE_ABSTRACT_TYPE (ClutterActorMeta,
+ clutter_actor_meta,
+ G_TYPE_INITIALLY_UNOWNED);
+
+static void
+clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
+ ClutterActor *actor)
+{
+ meta->priv->actor = actor;
+}
+
+static void
+clutter_actor_meta_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ clutter_actor_meta_set_name (meta, g_value_get_string (value));
+ break;
+
+ case PROP_ENABLED:
+ clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_actor_meta_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_ACTOR:
+ g_value_set_object (value, meta->priv->actor);
+ break;
+
+ case PROP_NAME:
+ g_value_set_string (value, meta->priv->name);
+ break;
+
+ case PROP_ENABLED:
+ g_value_set_boolean (value, meta->priv->is_enabled);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_actor_meta_finalize (GObject *gobject)
+{
+ ClutterActorMetaPrivate *priv = CLUTTER_ACTOR_META (gobject)->priv;
+
+ g_free (priv->name);
+
+ G_OBJECT_CLASS (clutter_actor_meta_parent_class)->finalize (gobject);
+}
+
+void
+clutter_actor_meta_class_init (ClutterActorMetaClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterActorMetaPrivate));
+
+ klass->set_actor = clutter_actor_meta_real_set_actor;
+
+ gobject_class->set_property = clutter_actor_meta_set_property;
+ gobject_class->get_property = clutter_actor_meta_get_property;
+ gobject_class->finalize = clutter_actor_meta_finalize;
+
+ /**
+ * ClutterActorMeta:actor:
+ *
+ * The #ClutterActor attached to the #ClutterActorMeta instance
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("actor",
+ "Actor",
+ "The actor attached to the meta",
+ CLUTTER_TYPE_ACTOR,
+ CLUTTER_PARAM_READABLE);
+ g_object_class_install_property (gobject_class, PROP_ACTOR, pspec);
+
+ /**
+ * ClutterActorMeta:name:
+ *
+ * The unique name to access the #ClutterActorMeta
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_string ("name",
+ "Name",
+ "The name of the meta",
+ NULL,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_NAME, pspec);
+
+ /**
+ * ClutterActorMeta:enabled:
+ *
+ * Whether or not the #ClutterActorMeta is enabled
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_boolean ("enabled",
+ "Enabled",
+ "Whether the meta is enabled",
+ TRUE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ENABLED, pspec);
+}
+
+void
+clutter_actor_meta_init (ClutterActorMeta *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ CLUTTER_TYPE_ACTOR_META,
+ ClutterActorMetaPrivate);
+
+ self->priv->is_enabled = TRUE;
+}
+
+/**
+ * clutter_actor_meta_set_name:
+ * @meta: a #ClutterActorMeta
+ * @name: the name of @meta
+ *
+ * Sets the name of @meta
+ *
+ * The name can be used to identify the #ClutterActorMeta instance
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_meta_set_name (ClutterActorMeta *meta,
+ const gchar *name)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
+
+ if (g_strcmp0 (meta->priv->name, name) == 0)
+ return;
+
+ g_free (meta->priv->name);
+ meta->priv->name = g_strdup (name);
+
+ g_object_notify (G_OBJECT (meta), "name");
+}
+
+/**
+ * clutter_actor_meta_get_name:
+ * @meta: a #ClutterActorMeta
+ *
+ * Retrieves the name set using clutter_actor_meta_set_name()
+ *
+ * Return value: (transfer none): the name of the #ClutterActorMeta
+ * instance, or %NULL if none was set. The returned string is owned
+ * by the #ClutterActorMeta instance and it should not be modified
+ * or freed
+ *
+ * Since: 1.4
+ */
+G_CONST_RETURN gchar *
+clutter_actor_meta_get_name (ClutterActorMeta *meta)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
+
+ return meta->priv->name;
+}
+
+/**
+ * clutter_actor_meta_set_enabled:
+ * @meta: a #ClutterActorMeta
+ * @is_enabled: whether @meta is enabled
+ *
+ * Sets whether @meta should be enabled or not
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
+ gboolean is_enabled)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
+
+ is_enabled = !!is_enabled;
+
+ if (meta->priv->is_enabled == is_enabled)
+ return;
+
+ meta->priv->is_enabled = is_enabled;
+
+ g_object_notify (G_OBJECT (meta), "enabled");
+}
+
+/**
+ * clutter_actor_meta_get_enabled:
+ * @meta: a #ClutterActorMeta
+ *
+ * Retrieves whether @meta is enabled
+ *
+ * Return value: %TRUE if the #ClutterActorMeta instance is enabled
+ *
+ * Since: 1.4
+ */
+gboolean
+clutter_actor_meta_get_enabled (ClutterActorMeta *meta)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), FALSE);
+
+ return meta->priv->is_enabled;
+}
+
+/*
+ * _clutter_actor_meta_set_actor
+ * @meta: a #ClutterActorMeta
+ * @actor: a #ClutterActor or %NULL
+ *
+ * Sets or unsets a back pointer to the #ClutterActor that owns
+ * the @meta
+ *
+ * Since: 1.4
+ */
+void
+_clutter_actor_meta_set_actor (ClutterActorMeta *meta,
+ ClutterActor *actor)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
+ g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
+
+ CLUTTER_ACTOR_META_GET_CLASS (meta)->set_actor (meta, actor);
+}
+
+/**
+ * clutter_actor_meta_get_actor:
+ * @meta: a #ClutterActorMeta
+ *
+ * Retrieves a pointer to the #ClutterActor that owns @meta
+ *
+ * Return value: (transfer none): a pointer to a #ClutterActor or %NULL
+ *
+ * Since: 1.4
+ */
+ClutterActor *
+clutter_actor_meta_get_actor (ClutterActorMeta *meta)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
+
+ return meta->priv->actor;
+}
+
+/*
+ * ClutterMetaGroup: a collection of ClutterActorMeta instances
+ */
+
+G_DEFINE_TYPE (ClutterMetaGroup, _clutter_meta_group, G_TYPE_OBJECT);
+
+static void
+_clutter_meta_group_dispose (GObject *gobject)
+{
+ _clutter_meta_group_clear_metas (CLUTTER_META_GROUP (gobject));
+
+ G_OBJECT_CLASS (_clutter_meta_group_parent_class)->dispose (gobject);
+}
+
+static void
+_clutter_meta_group_class_init (ClutterMetaGroupClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = _clutter_meta_group_dispose;
+}
+
+static void
+_clutter_meta_group_init (ClutterMetaGroup *self)
+{
+}
+
+/*
+ * _clutter_meta_group_add_meta:
+ * @group: a #ClutterMetaGroup
+ * @meta: a #ClutterActorMeta to add
+ *
+ * Adds @meta to @group
+ *
+ * This function will remove the floating reference of @meta or, if the
+ * floating reference has already been sunk, add a reference to it
+ */
+void
+_clutter_meta_group_add_meta (ClutterMetaGroup *group,
+ ClutterActorMeta *meta)
+{
+ if (meta->priv->actor != NULL)
+ {
+ g_warning ("The meta of type '%s' with name '%s' is "
+ "already attached to actor '%s'",
+ G_OBJECT_TYPE_NAME (meta),
+ meta->priv->name != NULL
+ ? meta->priv->name
+ : "",
+ clutter_actor_get_name (meta->priv->actor) != NULL
+ ? clutter_actor_get_name (meta->priv->actor)
+ : G_OBJECT_TYPE_NAME (meta->priv->actor));
+ return;
+ }
+
+ group->meta = g_list_append (group->meta, meta);
+ g_object_ref_sink (meta);
+
+ _clutter_actor_meta_set_actor (meta, group->actor);
+}
+
+/*
+ * _clutter_meta_group_remove_meta:
+ * @group: a #ClutterMetaGroup
+ * @meta: a #ClutterActorMeta to remove
+ *
+ * Removes @meta from @group and releases the reference being held on it
+ */
+void
+_clutter_meta_group_remove_meta (ClutterMetaGroup *group,
+ ClutterActorMeta *meta)
+{
+ if (meta->priv->actor != group->actor)
+ {
+ g_warning ("The meta of type '%s' with name '%s' is not "
+ "attached to the actor '%s'",
+ G_OBJECT_TYPE_NAME (meta),
+ meta->priv->name != NULL
+ ? meta->priv->name
+ : "",
+ clutter_actor_get_name (group->actor) != NULL
+ ? clutter_actor_get_name (group->actor)
+ : G_OBJECT_TYPE_NAME (group->actor));
+ return;
+ }
+
+ _clutter_actor_meta_set_actor (meta, NULL);
+
+ group->meta = g_list_remove (group->meta, meta);
+ g_object_unref (meta);
+}
+
+/*
+ * _clutter_meta_group_peek_metas:
+ * @group: a #ClutterMetaGroup
+ *
+ * Returns a pointer to the #ClutterActorMeta list
+ *
+ * Return value: a const pointer to the #GList of #ClutterActorMeta
+ */
+G_CONST_RETURN GList *
+_clutter_meta_group_peek_metas (ClutterMetaGroup *group)
+{
+ return group->meta;
+}
+
+/*
+ * _clutter_meta_group_clear_metas:
+ * @group: a #ClutterMetaGroup
+ *
+ * Clears @group of all #ClutterActorMeta instances and releases
+ * the reference on them
+ */
+void
+_clutter_meta_group_clear_metas (ClutterMetaGroup *group)
+{
+ g_list_foreach (group->meta, (GFunc) _clutter_actor_meta_set_actor, NULL);
+
+ g_list_foreach (group->meta, (GFunc) g_object_unref, NULL);
+ g_list_free (group->meta);
+ group->meta = NULL;
+}
+
+/*
+ * _clutter_meta_group_get_meta:
+ * @group: a #ClutterMetaGroup
+ * @name: the name of the #ClutterActorMeta to retrieve
+ *
+ * Retrieves a named #ClutterActorMeta from @group
+ *
+ * Return value: a #ClutterActorMeta for the given name, or %NULL
+ */
+ClutterActorMeta *
+_clutter_meta_group_get_meta (ClutterMetaGroup *group,
+ const gchar *name)
+{
+ GList *l;
+
+ for (l = group->meta; l != NULL; l = l->next)
+ {
+ ClutterActorMeta *meta = l->data;
+
+ if (g_strcmp0 (meta->priv->name, name) == 0)
+ return meta;
+ }
+
+ return NULL;
+}
diff --git a/clutter/clutter-actor-meta.h b/clutter/clutter-actor-meta.h
new file mode 100644
index 000000000..4c8ed5e01
--- /dev/null
+++ b/clutter/clutter-actor-meta.h
@@ -0,0 +1,84 @@
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_ACTOR_META_H__
+#define __CLUTTER_ACTOR_META_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_ACTOR_META (clutter_actor_meta_get_type ())
+#define CLUTTER_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMeta))
+#define CLUTTER_IS_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTOR_META))
+#define CLUTTER_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass))
+#define CLUTTER_IS_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTOR_META))
+#define CLUTTER_ACTOR_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass))
+
+typedef struct _ClutterActorMetaPrivate ClutterActorMetaPrivate;
+typedef struct _ClutterActorMetaClass ClutterActorMetaClass;
+
+/**
+ * ClutterActorMeta:
+ *
+ * The ClutterActorMeta structure contains only
+ * private data and should be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterActorMeta
+{
+ /*< private >*/
+ GInitiallyUnowned parent_instance;
+
+ ClutterActorMetaPrivate *priv;
+};
+
+/**
+ * ClutterActorMetaClass:
+ * @set_actor: virtual function, invoked when attaching and detaching
+ * a #ClutterActorMeta instance to a #ClutterActor
+ *
+ * The ClutterActorMetaClass structure contains
+ * only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterActorMetaClass
+{
+ /*< private >*/
+ GInitiallyUnownedClass parent_class;
+
+ /*< public >*/
+ void (* set_actor) (ClutterActorMeta *meta,
+ ClutterActor *actor);
+
+ /*< private >*/
+ void (* _clutter_meta1) (void);
+ void (* _clutter_meta2) (void);
+ void (* _clutter_meta3) (void);
+ void (* _clutter_meta4) (void);
+ void (* _clutter_meta5) (void);
+ void (* _clutter_meta6) (void);
+ void (* _clutter_meta7) (void);
+};
+
+GType clutter_actor_meta_get_type (void) G_GNUC_CONST;
+
+void clutter_actor_meta_set_name (ClutterActorMeta *meta,
+ const gchar *name);
+G_CONST_RETURN gchar *clutter_actor_meta_get_name (ClutterActorMeta *meta);
+void clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
+ gboolean is_enabled);
+gboolean clutter_actor_meta_get_enabled (ClutterActorMeta *meta);
+
+ClutterActor * clutter_actor_meta_get_actor (ClutterActorMeta *meta);
+
+/* private */
+void _clutter_actor_meta_set_actor (ClutterActorMeta *meta,
+ ClutterActor *actor);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_ACTOR_META_H__ */
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index 4e2f46b76..93ad88f00 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -155,6 +155,65 @@
* should read the documentation for the #ClutterUnits parser format for
* the valid units and syntax.
*
+ *
+ *
+ * Custom animatable properties
+ * #ClutterActor allows accessing properties of #ClutterAction
+ * and #ClutterConstraint instances associated to an actor instance
+ * for animation purposes.
+ * In order to access a specific #ClutterAction or a #ClutterConstraint
+ * property it is necessary to set the #ClutterActorMeta:name property on the
+ * given action or constraint.
+ * The property can be accessed using the the following syntax:
+ *
+ *
+ * @<section>.<meta-name>.<property-name>
+ *
+ *
+ * The initial @ is mandatory.
+ * The section fragment can be one between
+ * "actions" or "constraints".
+ * The meta-name fragment is the name of the
+ * action or constraint, as specified by the #ClutterActorMeta:name
+ * property.
+ * The property-name fragment is the name of the
+ * action or constraint property to be animated.
+ *
+ * Animating a constraint property
+ * The example below animates a #ClutterBindConstraint applied to an
+ * actor using clutter_actor_animate(). The rect has
+ * a binding constraint for the origin actor, and in
+ * its initial state is fully transparent and overlapping the actor to
+ * which is bound to.
+ *
+ * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
+ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
+ * clutter_actor_add_constraint (rect, constraint);
+ *
+ * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
+ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
+ * clutter_actor_add_constraint (rect, constraint);
+ *
+ * clutter_actor_set_reactive (rect, TRUE);
+ * clutter_actor_set_opacity (rect, 0);
+ *
+ * g_signal_connect (rect, "button-press-event",
+ * G_CALLBACK (on_button_press),
+ * NULL);
+ *
+ * On button press, the rectangle "slides" from behind the actor to
+ * which is bound to, using the #ClutterBindConstraint:offset property and
+ * the #ClutterActor:opacity property.
+ *
+ * float new_offset = clutter_actor_get_width (origin) + h_padding;
+ *
+ * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
+ * "opacity", 255,
+ * "@constraints.bind-x.offset", new_offset,
+ * NULL);
+ *
+ *
+ *
*/
/**
@@ -226,17 +285,23 @@
#endif
#include "clutter-actor.h"
+
+#include "clutter-action.h"
+#include "clutter-actor-meta-private.h"
+#include "clutter-animatable.h"
+#include "clutter-constraint.h"
#include "clutter-container.h"
-#include "clutter-main.h"
+#include "clutter-debug.h"
#include "clutter-enum-types.h"
-#include "clutter-scriptable.h"
-#include "clutter-script.h"
+#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
-#include "clutter-debug.h"
-#include "clutter-units.h"
#include "clutter-profile.h"
+#include "clutter-scriptable.h"
+#include "clutter-script.h"
#include "clutter-stage.h"
+#include "clutter-units.h"
+
#include "cogl/cogl.h"
typedef struct _ShaderData ShaderData;
@@ -391,6 +456,9 @@ struct _ClutterActorPrivate
* See clutter_actor_queue_clipped_redraw() for details.
*/
const ClutterActorBox *oob_queue_redraw_clip;
+
+ ClutterMetaGroup *actions;
+ ClutterMetaGroup *constraints;
};
enum
@@ -471,7 +539,10 @@ enum
PROP_SHOW_ON_SET_PARENT,
PROP_TEXT_DIRECTION,
- PROP_HAS_POINTER
+ PROP_HAS_POINTER,
+
+ PROP_ACTIONS,
+ PROP_CONSTRAINTS
};
enum
@@ -506,6 +577,7 @@ enum
static guint actor_signals[LAST_SIGNAL] = { 0, };
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
+static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
static void _clutter_actor_apply_modelview_transform (ClutterActor *self);
@@ -571,7 +643,9 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor,
clutter_actor,
G_TYPE_INITIALLY_UNOWNED,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
- clutter_scriptable_iface_init));
+ clutter_scriptable_iface_init)
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
+ clutter_animatable_iface_init));
static const gchar *
get_actor_debug_name (ClutterActor *actor)
@@ -2892,6 +2966,14 @@ clutter_actor_set_property (GObject *object,
clutter_actor_set_text_direction (actor, g_value_get_enum (value));
break;
+ case PROP_ACTIONS:
+ clutter_actor_add_action (actor, g_value_get_object (value));
+ break;
+
+ case PROP_CONSTRAINTS:
+ clutter_actor_add_constraint (actor, g_value_get_object (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3199,12 +3281,18 @@ clutter_actor_dispose (GObject *object)
destroy_shader_data (self);
- if (priv->pango_context)
+ if (priv->pango_context != NULL)
{
g_object_unref (priv->pango_context);
priv->pango_context = NULL;
}
+ if (priv->actions != NULL)
+ {
+ g_object_unref (priv->actions);
+ priv->actions = NULL;
+ }
+
g_signal_emit (self, actor_signals[DESTROY], 0);
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
@@ -3999,6 +4087,34 @@ clutter_actor_class_init (ClutterActorClass *klass)
PROP_HAS_POINTER,
pspec);
+ /**
+ * ClutterActor:actions:
+ *
+ * Adds a #ClutterAction to the actor
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("actions",
+ "Actions",
+ "Adds an action to the actor",
+ CLUTTER_TYPE_ACTION,
+ CLUTTER_PARAM_WRITABLE);
+ g_object_class_install_property (object_class, PROP_ACTIONS, pspec);
+
+ /**
+ * ClutterActor:constraints:
+ *
+ * Adds a #ClutterConstaint to the actor
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("constraints",
+ "Constraints",
+ "Adds a constraint to the actor",
+ CLUTTER_TYPE_CONSTRAINT,
+ CLUTTER_PARAM_WRITABLE);
+ g_object_class_install_property (object_class, PROP_CONSTRAINTS, pspec);
+
/**
* ClutterActor::destroy:
* @actor: the object which received the signal
@@ -8104,6 +8220,158 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
iface->set_custom_property = clutter_actor_set_custom_property;
}
+static ClutterActorMeta *
+get_meta_from_animation_property (ClutterActor *actor,
+ const gchar *name,
+ gchar **name_p)
+{
+ ClutterActorPrivate *priv = actor->priv;
+ ClutterActorMeta *meta = NULL;
+ gchar **tokens;
+
+ /* if this is not a special property, fall through */
+ if (name[0] != '@')
+ return NULL;
+
+ /* detect the properties named using the following spec:
+ *
+ * @..
+ *
+ * where can be one of the following:
+ *
+ * - actions
+ * - constraints
+ *
+ * and is the name set on a specific ActorMeta
+ */
+
+ tokens = g_strsplit (name + 1, ".", -1);
+ if (tokens == NULL || g_strv_length (tokens) != 3)
+ {
+ CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
+ name + 1);
+ g_strfreev (tokens);
+ return NULL;
+ }
+
+ if (strcmp (tokens[0], "actions") == 0)
+ meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
+
+ if (strcmp (tokens[0], "constraints") == 0)
+ meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
+
+ if (name_p != NULL)
+ *name_p = g_strdup (tokens[2]);
+
+ CLUTTER_NOTE (ANIMATION,
+ "Looking for property '%s' of object '%s' in section '%s'",
+ tokens[2],
+ tokens[1],
+ tokens[0]);
+
+ g_strfreev (tokens);
+
+ return meta;
+}
+
+static GParamSpec *
+clutter_actor_find_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name)
+{
+ ClutterActorMeta *meta = NULL;
+ GObjectClass *klass = NULL;
+ GParamSpec *pspec = NULL;
+ gchar *p_name = NULL;
+
+ meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
+ property_name,
+ &p_name);
+
+ if (meta != NULL)
+ {
+ klass = G_OBJECT_GET_CLASS (meta);
+
+ pspec = g_object_class_find_property (klass, p_name);
+
+ g_free (p_name);
+ }
+ else
+ {
+ klass = G_OBJECT_GET_CLASS (animatable);
+
+ pspec = g_object_class_find_property (klass, property_name);
+ }
+
+ return pspec;
+}
+
+static void
+clutter_actor_get_initial_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ GValue *initial)
+{
+ ClutterActorMeta *meta = NULL;
+ gchar *p_name = NULL;
+
+ meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
+ property_name,
+ &p_name);
+
+ if (meta != NULL)
+ g_object_get_property (G_OBJECT (meta), p_name, initial);
+ else
+ g_object_get_property (G_OBJECT (animatable), property_name, initial);
+
+ g_free (p_name);
+}
+
+static void
+clutter_actor_set_final_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *final)
+{
+ ClutterActorMeta *meta = NULL;
+ gchar *p_name = NULL;
+
+ meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
+ property_name,
+ &p_name);
+ if (meta != NULL)
+ g_object_set_property (G_OBJECT (meta), p_name, final);
+ else
+ g_object_set_property (G_OBJECT (animatable), property_name, final);
+
+ g_free (p_name);
+}
+
+static gboolean
+clutter_actor_animate_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial,
+ const GValue *final,
+ gdouble progress,
+ GValue *new_value)
+{
+ ClutterInterval *interval;
+
+ interval = clutter_animation_get_interval (animation, property_name);
+
+ return clutter_interval_compute_value (interval, progress, new_value);
+}
+
+static void
+clutter_animatable_iface_init (ClutterAnimatableIface *iface)
+{
+ iface->animate_property = clutter_actor_animate_property;
+ iface->find_property = clutter_actor_find_property;
+ iface->get_initial_state = clutter_actor_get_initial_state;
+ iface->set_final_state = clutter_actor_set_final_state;
+}
+
/**
* clutter_actor_transform_stage_point
* @self: A #ClutterActor
@@ -10172,3 +10440,414 @@ clutter_actor_has_allocation (ClutterActor *self)
CLUTTER_ACTOR_IS_VISIBLE (self) &&
!priv->needs_allocation;
}
+
+/**
+ * clutter_actor_add_action:
+ * @self: a #ClutterActor
+ * @action: a #ClutterAction
+ *
+ * Adds @action to the list of actions applied to @self
+ *
+ * A #ClutterAction can only belong to one actor at a time
+ *
+ * The #ClutterActor will hold a reference on @action until either
+ * clutter_actor_remove_action() or clutter_actor_clear_actions()
+ * is called
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_action (ClutterActor *self,
+ ClutterAction *action)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (CLUTTER_IS_ACTION (action));
+
+ priv = self->priv;
+
+ if (priv->actions == NULL)
+ {
+ priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
+ priv->actions->actor = self;
+ }
+
+ _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
+
+ g_object_notify (G_OBJECT (self), "actions");
+}
+
+/**
+ * clutter_actor_add_action_with_name:
+ * @self: a #ClutterActor
+ * @name: the name to set on the action
+ * @action: a #ClutterAction
+ *
+ * A convenience function for setting the name of a #ClutterAction
+ * while adding it to the list of actions applied to @self
+ *
+ * This function is the logical equivalent of:
+ *
+ * |[
+ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
+ * clutter_actor_add_action (self, action);
+ * ]|
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_action_with_name (ClutterActor *self,
+ const gchar *name,
+ ClutterAction *action)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (CLUTTER_IS_ACTION (self));
+
+ clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
+ clutter_actor_add_action (self, action);
+}
+
+/**
+ * clutter_actor_remove_action:
+ * @self: a #ClutterActor
+ * @action: a #ClutterAction
+ *
+ * Removes @action from the list of actions applied to @self
+ *
+ * The reference held by @self on the #ClutterAction will be released
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_action (ClutterActor *self,
+ ClutterAction *action)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (CLUTTER_IS_ACTION (action));
+
+ priv = self->priv;
+
+ if (priv->actions == NULL)
+ return;
+
+ _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
+
+ g_object_notify (G_OBJECT (self), "actions");
+}
+
+/**
+ * clutter_actor_remove_action_by_name:
+ * @self: a #ClutterActor
+ * @name: the name of the action to remove
+ *
+ * Removes the #ClutterAction with the given name from the list
+ * of actions applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_action_by_name (ClutterActor *self,
+ const gchar *name)
+{
+ ClutterActorPrivate *priv;
+ ClutterActorMeta *meta;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (name != NULL);
+
+ priv = self->priv;
+
+ if (priv->actions == NULL)
+ return;
+
+ meta = _clutter_meta_group_get_meta (priv->actions, name);
+ if (meta == NULL)
+ return;
+
+ _clutter_meta_group_remove_meta (priv->actions, meta);
+
+ g_object_notify (G_OBJECT (self), "actions");
+}
+
+/**
+ * clutter_actor_get_actions:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the list of actions applied to @self
+ *
+ * Return value: (transfer container) (element-type ClutterAction): a copy
+ * of the list of #ClutterActions. The contents of the list are
+ * owned by the #ClutterActor. Use g_list_free() to free the resources
+ * allocated by the returned #GList
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_actor_get_actions (ClutterActor *self)
+{
+ const GList *actions;
+
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+ if (self->priv->actions == NULL)
+ return NULL;
+
+ actions = _clutter_meta_group_peek_metas (self->priv->actions);
+
+ return g_list_copy ((GList *) actions);
+}
+
+/**
+ * clutter_actor_get_action:
+ * @self: a #ClutterActor
+ * @name: the name of the action to retrieve
+ *
+ * Retrieves the #ClutterAction with the given name in the list
+ * of actions applied to @self
+ *
+ * Return value: (transfer none): a #ClutterAction for the given
+ * name, or %NULL. The returned #ClutterAction is owned by the
+ * actor and it should not be unreferenced directly
+ *
+ * Since: 1.4
+ */
+ClutterAction *
+clutter_actor_get_action (ClutterActor *self,
+ const gchar *name)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (self->priv->actions == NULL)
+ return NULL;
+
+ return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
+}
+
+/**
+ * clutter_actor_clear_actions:
+ * @self: a #ClutterActor
+ *
+ * Clears the list of actions applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_clear_actions (ClutterActor *self)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ if (self->priv->actions == NULL)
+ return;
+
+ _clutter_meta_group_clear_metas (self->priv->actions);
+}
+
+/**
+ * clutter_actor_add_constraint:
+ * @self: a #ClutterActor
+ * @constraint: a #ClutterConstraint
+ *
+ * Adds @constraint to the list of #ClutterConstraints applied
+ * to @self
+ *
+ * The #ClutterActor will hold a reference on the @constraint until
+ * either clutter_actor_remove_constraint() or
+ * clutter_actor_clear_constraints() is called.
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_constraint (ClutterActor *self,
+ ClutterConstraint *constraint)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
+
+ priv = self->priv;
+
+ if (priv->constraints == NULL)
+ {
+ priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
+ priv->constraints->actor = self;
+ }
+
+ _clutter_meta_group_add_meta (priv->constraints,
+ CLUTTER_ACTOR_META (constraint));
+
+ g_object_notify (G_OBJECT (self), "constraints");
+}
+
+/**
+ * clutter_actor_add_constraint_with_name:
+ * @self: a #ClutterActor
+ * @name: the name to set on the constraint
+ * @constraint: a #ClutterConstraint
+ *
+ * A convenience function for setting the name of a #ClutterConstraint
+ * while adding it to the list of constraints applied to @self
+ *
+ * This function is the logical equivalent of:
+ *
+ * |[
+ * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
+ * clutter_actor_add_constraint (self, constraint);
+ * ]|
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_add_constraint_with_name (ClutterActor *self,
+ const gchar *name,
+ ClutterConstraint *constraint)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
+
+ clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
+ clutter_actor_add_constraint (self, constraint);
+}
+
+/**
+ * clutter_actor_remove_constraint:
+ * @self: a #ClutterActor
+ * @constraint: a #ClutterConstraint
+ *
+ * Removes @constraint from the list of constraints applied to @self
+ *
+ * The reference held by @self on the #ClutterConstraint will be released
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_constraint (ClutterActor *self,
+ ClutterConstraint *constraint)
+{
+ ClutterActorPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
+
+ priv = self->priv;
+
+ if (priv->constraints == NULL)
+ return;
+
+ _clutter_meta_group_remove_meta (priv->constraints,
+ CLUTTER_ACTOR_META (constraint));
+
+ g_object_notify (G_OBJECT (self), "constraints");
+}
+
+/**
+ * clutter_actor_remove_constraint_by_name:
+ * @self: a #ClutterActor
+ * @name: the name of the constraint to remove
+ *
+ * Removes the #ClutterConstraint with the given name from the list
+ * of constraints applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_remove_constraint_by_name (ClutterActor *self,
+ const gchar *name)
+{
+ ClutterActorPrivate *priv;
+ ClutterActorMeta *meta;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+ g_return_if_fail (name != NULL);
+
+ priv = self->priv;
+
+ if (priv->constraints == NULL)
+ return;
+
+ meta = _clutter_meta_group_get_meta (priv->constraints, name);
+ if (meta == NULL)
+ return;
+
+ _clutter_meta_group_remove_meta (priv->constraints, meta);
+}
+
+/**
+ * clutter_actor_get_constraints:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the list of constraints applied to @self
+ *
+ * Return value: (transfer container) (element-type ClutterConstraint): a copy
+ * of the list of #ClutterConstraints. The contents of the list are
+ * owned by the #ClutterActor. Use g_list_free() to free the resources
+ * allocated by the returned #GList
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_actor_get_constraints (ClutterActor *self)
+{
+ const GList *constraints;
+
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+ if (self->priv->constraints == NULL)
+ return NULL;
+
+ constraints = _clutter_meta_group_peek_metas (self->priv->constraints);
+
+ return g_list_copy ((GList *) constraints);
+}
+
+/**
+ * clutter_actor_get_constraint:
+ * @self: a #ClutterActor
+ * @name: the name of the constraint to retrieve
+ *
+ * Retrieves the #ClutterConstraint with the given name in the list
+ * of constraints applied to @self
+ *
+ * Return value: (transfer none): a #ClutterConstraint for the given
+ * name, or %NULL. The returned #ClutterConstraint is owned by the
+ * actor and it should not be unreferenced directly
+ *
+ * Since: 1.4
+ */
+ClutterConstraint *
+clutter_actor_get_constraint (ClutterActor *self,
+ const gchar *name)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ if (self->priv->constraints == NULL)
+ return NULL;
+
+ return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
+}
+
+/**
+ * clutter_actor_clear_constraints:
+ * @self: a #ClutterActor
+ *
+ * Clears the list of constraints applied to @self
+ *
+ * Since: 1.4
+ */
+void
+clutter_actor_clear_constraints (ClutterActor *self)
+{
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ if (self->priv->constraints == NULL)
+ return;
+
+ _clutter_meta_group_clear_metas (self->priv->constraints);
+}
diff --git a/clutter/clutter-align-constraint.c b/clutter/clutter-align-constraint.c
new file mode 100644
index 000000000..0ed459c8e
--- /dev/null
+++ b/clutter/clutter-align-constraint.c
@@ -0,0 +1,335 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+/**
+ * SECTION:clutter-align-constraint
+ * @Title: ClutterAlignConstraint
+ * @Short_Description: A constraint aligning the position of an actor
+ *
+ * #ClutterAlignConstraint is a #ClutterConstraint that aligns the position
+ * of the #ClutterActor to which it is applied to the size of another
+ * #ClutterActor using an alignment factor
+ *
+ * #ClutterAlignConstraint is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-align-constraint.h"
+
+#include "clutter-constraint.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-private.h"
+
+#define CLUTTER_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass))
+#define CLUTTER_IS_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT))
+#define CLUTTER_ALIGN_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass))
+
+typedef struct _ClutterAlignConstraintClass ClutterAlignConstraintClass;
+
+struct _ClutterAlignConstraint
+{
+ ClutterConstraint parent_instance;
+
+ ClutterActor *source;
+ ClutterAlignAxis align_axis;
+ gfloat factor;
+};
+
+struct _ClutterAlignConstraintClass
+{
+ ClutterConstraintClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_SOURCE,
+ PROP_ALIGN_AXIS,
+ PROP_FACTOR
+};
+
+G_DEFINE_TYPE (ClutterAlignConstraint,
+ clutter_align_constraint,
+ CLUTTER_TYPE_CONSTRAINT);
+
+static void
+update_actor_position (ClutterAlignConstraint *align)
+{
+ gfloat source_width, source_height;
+ gfloat actor_width, actor_height;
+ ClutterActor *actor;
+
+ if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (align)))
+ return;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (align));
+ if (actor == NULL)
+ return;
+
+ clutter_actor_get_size (align->source, &source_width, &source_height);
+ clutter_actor_get_size (actor, &actor_width, &actor_height);
+
+ switch (align->align_axis)
+ {
+ case CLUTTER_ALIGN_X_AXIS:
+ clutter_actor_set_x (actor, (source_width - actor_width) * align->factor);
+ break;
+
+ case CLUTTER_ALIGN_Y_AXIS:
+ clutter_actor_set_y (actor, (source_height - actor_height) * align->factor);
+ break;
+ }
+}
+
+static void
+source_position_changed (GObject *gobject,
+ GParamSpec *pspec,
+ ClutterAlignConstraint *align)
+{
+ if (strcmp (pspec->name, "width") == 0 ||
+ strcmp (pspec->name, "height") == 0)
+ {
+ update_actor_position (align);
+ }
+}
+
+static void
+source_destroyed (ClutterActor *actor,
+ ClutterAlignConstraint *align)
+{
+ align->source = NULL;
+}
+
+static void
+_clutter_align_constraint_set_source (ClutterAlignConstraint *align,
+ ClutterActor *source)
+{
+ ClutterActor *old_source = align->source;
+
+ if (old_source != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (old_source,
+ G_CALLBACK (source_destroyed),
+ align);
+ g_signal_handlers_disconnect_by_func (old_source,
+ G_CALLBACK (source_position_changed),
+ align);
+ }
+
+ align->source = source;
+ g_signal_connect (align->source, "notify",
+ G_CALLBACK (source_position_changed),
+ align);
+ g_signal_connect (align->source, "destroy",
+ G_CALLBACK (source_destroyed),
+ align);
+
+ update_actor_position (align);
+
+ g_object_notify (G_OBJECT (align), "source");
+}
+
+static void
+_clutter_align_constraint_set_align_axis (ClutterAlignConstraint *align,
+ ClutterAlignAxis axis)
+{
+ if (align->align_axis == axis)
+ return;
+
+ align->align_axis = axis;
+
+ update_actor_position (align);
+
+ g_object_notify (G_OBJECT (align), "align-axis");
+}
+
+static void
+_clutter_align_constraint_set_factor (ClutterAlignConstraint *align,
+ gfloat factor)
+{
+ align->factor = CLAMP (factor, 0.0, 1.0);
+
+ update_actor_position (align);
+
+ g_object_notify (G_OBJECT (align), "factor");
+}
+
+static void
+clutter_align_constraint_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ _clutter_align_constraint_set_source (align, g_value_get_object (value));
+ break;
+
+ case PROP_ALIGN_AXIS:
+ _clutter_align_constraint_set_align_axis (align, g_value_get_enum (value));
+ break;
+
+ case PROP_FACTOR:
+ _clutter_align_constraint_set_factor (align, g_value_get_float (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_align_constraint_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ g_value_set_object (value, align->source);
+ break;
+
+ case PROP_ALIGN_AXIS:
+ g_value_set_enum (value, align->align_axis);
+ break;
+
+ case PROP_FACTOR:
+ g_value_set_float (value, align->factor);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ gobject_class->set_property = clutter_align_constraint_set_property;
+ gobject_class->get_property = clutter_align_constraint_get_property;
+
+ /**
+ * ClutterAlignConstraint:source:
+ *
+ * The #ClutterActor used as the source for the alignment
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("source",
+ "Source",
+ "The source of the alignment",
+ CLUTTER_TYPE_ACTOR,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_SOURCE, pspec);
+
+ /**
+ * ClutterAlignConstraint:align-axis:
+ *
+ * The axis to be used to compute the alignment
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_enum ("align-axis",
+ "Align Axis",
+ "The axis to align the position to",
+ CLUTTER_TYPE_ALIGN_AXIS,
+ CLUTTER_ALIGN_X_AXIS,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_ALIGN_AXIS, pspec);
+
+ /**
+ * ClutterAlignConstraint:factor:
+ *
+ * The alignment factor, as a normalized value between 0.0 and 1.0
+ *
+ * The #ClutterAlignConstraint:factor depends on the
+ * #ClutterAlignConstraint:align-axis value: with %CLUTTER_ALIGN_X_AXIS,
+ * 0.0 means left and 1.0 means right; with %CLUTTER_ALIGN_Y_AXIS, 0.0
+ * means top and 1.0 means bottom
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_float ("factor",
+ "Factor",
+ "The alignment factor, between 0.0 and 1.0",
+ 0.0, 1.0,
+ 0.0,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_FACTOR, pspec);
+}
+
+static void
+clutter_align_constraint_init (ClutterAlignConstraint *self)
+{
+ self->source = NULL;
+ self->align_axis = CLUTTER_ALIGN_X_AXIS;
+ self->factor = 0.0f;
+}
+
+/**
+ * clutter_align_constraint_new:
+ * @source: the #ClutterActor to use as the source of the alignment
+ * @axis: the axis to be used to compute the alignment
+ * @factor: the alignment factor, between 0.0 and 1.0
+ *
+ * Creates a new constraint, aligning a #ClutterActor's position with
+ * regards of the size of the actor to @source, with the given alignment
+ * @factor
+ *
+ * Return value: the newly created #ClutterAlignConstraint
+ *
+ * Since: 1.4
+ */
+ClutterConstraint *
+clutter_align_constraint_new (ClutterActor *source,
+ ClutterAlignAxis axis,
+ gfloat factor)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (source), NULL);
+
+ return g_object_new (CLUTTER_TYPE_ALIGN_CONSTRAINT,
+ "source", source,
+ "align-axis", axis,
+ "factor", factor,
+ NULL);
+}
diff --git a/clutter/clutter-align-constraint.h b/clutter/clutter-align-constraint.h
new file mode 100644
index 000000000..c2289c9ee
--- /dev/null
+++ b/clutter/clutter-align-constraint.h
@@ -0,0 +1,73 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_ALIGN_CONSTRAINT_H__
+#define __CLUTTER_ALIGN_CONSTRAINT_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_ALIGN_CONSTRAINT (clutter_align_constraint_get_type ())
+#define CLUTTER_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraint))
+#define CLUTTER_IS_ALIGN_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT))
+
+/**
+ * ClutterAlignConstraint:
+ *
+ * ClutterAlignConstraint is an opaque structure
+ * whose members cannot be directly accesses
+ *
+ * Since: 1.4
+ */
+typedef struct _ClutterAlignConstraint ClutterAlignConstraint;
+
+/**
+ * ClutterAlignAxis:
+ * @CLUTTER_ALIGN_X_AXIS: Maintain the alignment on the X axis
+ * @CLUTTER_ALIGN_Y_AXIS: Maintain the alignment on the Y axis
+ *
+ * Specifies the axis on which #ClutterAlignConstraint should maintain
+ * the alignment
+ *
+ * Since: 1.4
+ */
+typedef enum { /*< prefix=CLUTTER_ALIGN >*/
+ CLUTTER_ALIGN_X_AXIS,
+ CLUTTER_ALIGN_Y_AXIS,
+} ClutterAlignAxis;
+
+GType clutter_align_constraint_get_type (void) G_GNUC_CONST;
+
+ClutterConstraint *clutter_align_constraint_new (ClutterActor *source,
+ ClutterAlignAxis axis,
+ gfloat factor);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_ALIGN_CONSTRAINT_H__ */
diff --git a/clutter/clutter-animatable.c b/clutter/clutter-animatable.c
index e448a694f..0674abf7c 100644
--- a/clutter/clutter-animatable.c
+++ b/clutter/clutter-animatable.c
@@ -124,3 +124,101 @@ clutter_animatable_animate_property (ClutterAnimatable *animatable,
return res;
}
+
+/**
+ * clutter_animatable_find_property:
+ * @animatable: a #ClutterAnimatable
+ * @animation: a #ClutterAnimation
+ * @property_name: the name of the animatable property to find
+ *
+ * Finds the #GParamSpec for @property_name
+ *
+ * Return value: (transfer none): The #GParamSpec for the given property
+ * or %NULL
+ *
+ * Since: 1.4
+ */
+GParamSpec *
+clutter_animatable_find_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name)
+{
+ ClutterAnimatableIface *iface;
+
+ g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL);
+ g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ CLUTTER_NOTE (ANIMATION, "Looking for property '%s'", property_name);
+
+ iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
+ if (iface->find_property != NULL)
+ return iface->find_property (animatable, animation, property_name);
+
+ return g_object_class_find_property (G_OBJECT_GET_CLASS (animatable),
+ property_name);
+}
+
+/**
+ * clutter_animatable_get_initial_state:
+ * @animatable: a #ClutterAnimatable
+ * @animation: a #ClutterAnimation
+ * @property_name: the name of the animatable property to retrieve
+ * @value: a #GValue initialized to the type of the property to retrieve
+ *
+ * Retrieves the current state of @property_name and sets @value with it
+ *
+ * Since: 1.4
+ */
+void
+clutter_animatable_get_initial_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ GValue *value)
+{
+ ClutterAnimatableIface *iface;
+
+ g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
+ g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
+ g_return_if_fail (property_name != NULL);
+
+ CLUTTER_NOTE (ANIMATION, "Getting initial state of '%s'", property_name);
+
+ iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
+ if (iface->get_initial_state != NULL)
+ iface->get_initial_state (animatable, animation, property_name, value);
+ else
+ g_object_get_property (G_OBJECT (animatable), property_name, value);
+}
+
+/**
+ * clutter_animatable_set_final_state:
+ * @animatable: a #ClutterAnimatable
+ * @animation: a #ClutterAnimation
+ * @property_name: the name of the animatable property to set
+ * @value: the value of the animatable property to set
+ *
+ * Sets the current state of @property_name to @value
+ *
+ * Since: 1.4
+ */
+void
+clutter_animatable_set_final_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *value)
+{
+ ClutterAnimatableIface *iface;
+
+ g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
+ g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
+ g_return_if_fail (property_name != NULL);
+
+ CLUTTER_NOTE (ANIMATION, "Setting state of property '%s'", property_name);
+
+ iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
+ if (iface->set_final_state != NULL)
+ iface->set_final_state (animatable, animation, property_name, value);
+ else
+ g_object_set_property (G_OBJECT (animatable), property_name, value);
+}
diff --git a/clutter/clutter-animatable.h b/clutter/clutter-animatable.h
index a82d13a4b..bddcc5ed0 100644
--- a/clutter/clutter-animatable.h
+++ b/clutter/clutter-animatable.h
@@ -52,7 +52,14 @@ typedef struct _ClutterAnimatableIface ClutterAnimatableIface;
/**
* ClutterAnimatableIface:
- * @animate_property: virtual function for animating a property
+ * @animate_property: virtual function for custom interpolation of a
+ * property
+ * @find_property: virtual function for retrieving the #GParamSpec of
+ * an animatable property
+ * @get_initial_state: virtual function for retrieving the initial
+ * state of an animatable property
+ * @set_final_state: virtual function for setting the state of an
+ * animatable property
*
* Base interface for #GObjects that can be animated by a
* a #ClutterAnimation.
@@ -65,24 +72,47 @@ struct _ClutterAnimatableIface
GTypeInterface parent_iface;
/*< public >*/
- gboolean (* animate_property) (ClutterAnimatable *animatable,
- ClutterAnimation *animation,
- const gchar *property_name,
- const GValue *initial_value,
- const GValue *final_value,
- gdouble progress,
- GValue *value);
+ gboolean (* animate_property) (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial_value,
+ const GValue *final_value,
+ gdouble progress,
+ GValue *value);
+ GParamSpec *(* find_property) (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name);
+ void (* get_initial_state) (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ GValue *value);
+ void (* set_final_state) (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *value);
};
GType clutter_animatable_get_type (void) G_GNUC_CONST;
-gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable,
- ClutterAnimation *animation,
- const gchar *property_name,
- const GValue *initial_value,
- const GValue *final_value,
- gdouble progress,
- GValue *value);
+gboolean clutter_animatable_animate_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial_value,
+ const GValue *final_value,
+ gdouble progress,
+ GValue *value);
+
+GParamSpec *clutter_animatable_find_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name);
+void clutter_animatable_get_initial_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ GValue *value);
+void clutter_animatable_set_final_state (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *value);
G_END_DECLS
diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c
index f7d8711b3..dd9599af3 100644
--- a/clutter/clutter-animation.c
+++ b/clutter/clutter-animation.c
@@ -212,6 +212,7 @@ static void
clutter_animation_real_completed (ClutterAnimation *self)
{
ClutterAnimationPrivate *priv = self->priv;
+ ClutterAnimatable *animatable = NULL;
ClutterAnimation *animation;
ClutterTimeline *timeline;
ClutterTimelineDirection direction;
@@ -221,6 +222,9 @@ clutter_animation_real_completed (ClutterAnimation *self)
timeline = clutter_animation_get_timeline (self);
direction = clutter_timeline_get_direction (timeline);
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ animatable = CLUTTER_ANIMATABLE (priv->object);
+
/* explicitly set the final state of the animation */
CLUTTER_NOTE (ANIMATION, "Set final state on object [%p]", priv->object);
g_hash_table_iter_init (&iter, priv->properties);
@@ -235,7 +239,12 @@ clutter_animation_real_completed (ClutterAnimation *self)
else
p_value = clutter_interval_peek_initial_value (interval);
- g_object_set_property (priv->object, p_name, p_value);
+ if (animatable != NULL)
+ clutter_animatable_set_final_state (animatable, self,
+ p_name,
+ p_value);
+ else
+ g_object_set_property (priv->object, p_name, p_value);
}
/* at this point, if this animation was created by clutter_actor_animate()
@@ -580,6 +589,7 @@ clutter_animation_init (ClutterAnimation *self)
static inline void
clutter_animation_bind_property_internal (ClutterAnimation *animation,
+ const gchar *property_name,
GParamSpec *pspec,
ClutterInterval *interval)
{
@@ -589,17 +599,18 @@ clutter_animation_bind_property_internal (ClutterAnimation *animation,
{
g_warning ("Cannot bind property '%s': the interval is out "
"of bounds",
- pspec->name);
+ property_name);
return;
}
g_hash_table_insert (priv->properties,
- g_strdup (pspec->name),
+ g_strdup (property_name),
g_object_ref_sink (interval));
}
static inline void
clutter_animation_update_property_internal (ClutterAnimation *animation,
+ const gchar *property_name,
GParamSpec *pspec,
ClutterInterval *interval)
{
@@ -609,12 +620,12 @@ clutter_animation_update_property_internal (ClutterAnimation *animation,
{
g_warning ("Cannot bind property '%s': the interval is out "
"of bounds",
- pspec->name);
+ property_name);
return;
}
g_hash_table_replace (priv->properties,
- g_strdup (pspec->name),
+ g_strdup (property_name),
g_object_ref_sink (interval));
}
@@ -624,7 +635,6 @@ clutter_animation_validate_bind (ClutterAnimation *animation,
GType argtype)
{
ClutterAnimationPrivate *priv;
- GObjectClass *klass;
GParamSpec *pspec;
GType pspec_type;
@@ -647,9 +657,22 @@ clutter_animation_validate_bind (ClutterAnimation *animation,
return NULL;
}
- klass = G_OBJECT_GET_CLASS (priv->object);
- pspec = g_object_class_find_property (klass, property_name);
- if (!pspec)
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ {
+ ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object);
+
+ pspec = clutter_animatable_find_property (animatable,
+ animation,
+ property_name);
+ }
+ else
+ {
+ GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object);
+
+ pspec = g_object_class_find_property (klass, property_name);
+ }
+
+ if (pspec == NULL)
{
g_warning ("Cannot bind property '%s': objects of type '%s' have "
"no such property",
@@ -715,7 +738,9 @@ clutter_animation_bind_interval (ClutterAnimation *animation,
if (pspec == NULL)
return NULL;
- clutter_animation_bind_property_internal (animation, pspec, interval);
+ clutter_animation_bind_property_internal (animation, property_name,
+ pspec,
+ interval);
return animation;
}
@@ -760,12 +785,21 @@ clutter_animation_bind (ClutterAnimation *animation,
return NULL;
g_value_init (&initial, G_PARAM_SPEC_VALUE_TYPE (pspec));
- g_object_get_property (priv->object, property_name, &initial);
+
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object),
+ animation,
+ property_name,
+ &initial);
+ else
+ g_object_get_property (priv->object, property_name, &initial);
interval = clutter_interval_new_with_values (type, &initial, final);
g_value_unset (&initial);
- clutter_animation_bind_property_internal (animation, pspec, interval);
+ clutter_animation_bind_property_internal (animation, property_name,
+ pspec,
+ interval);
return animation;
}
@@ -845,7 +879,6 @@ clutter_animation_update_interval (ClutterAnimation *animation,
ClutterInterval *interval)
{
ClutterAnimationPrivate *priv;
- GObjectClass *klass;
GParamSpec *pspec;
GType pspec_type, int_type;
@@ -863,9 +896,22 @@ clutter_animation_update_interval (ClutterAnimation *animation,
return;
}
- klass = G_OBJECT_GET_CLASS (priv->object);
- pspec = g_object_class_find_property (klass, property_name);
- if (!pspec)
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ {
+ ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (priv->object);
+
+ pspec = clutter_animatable_find_property (animatable,
+ animation,
+ property_name);
+ }
+ else
+ {
+ GObjectClass *klass = G_OBJECT_GET_CLASS (priv->object);
+
+ pspec = g_object_class_find_property (klass, property_name);
+ }
+
+ if (pspec == NULL)
{
g_warning ("Cannot update property '%s': objects of type '%s' have "
"no such property",
@@ -889,7 +935,9 @@ clutter_animation_update_interval (ClutterAnimation *animation,
return;
}
- clutter_animation_update_property_internal (animation, pspec, interval);
+ clutter_animation_update_property_internal (animation, property_name,
+ pspec,
+ interval);
}
/**
@@ -1050,7 +1098,14 @@ on_alpha_notify (GObject *gobject,
}
if (apply)
- g_object_set_property (priv->object, p_name, &value);
+ {
+ if (is_animatable)
+ clutter_animatable_set_final_state (animatable, animation,
+ p_name,
+ &value);
+ else
+ g_object_set_property (priv->object, p_name, &value);
+ }
g_value_unset (&value);
}
@@ -1688,26 +1743,41 @@ done:
GValue cur_value = { 0, };
g_value_init (&cur_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
- g_object_get_property (priv->object, property_name, &cur_value);
+
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (priv->object),
+ animation,
+ property_name,
+ &cur_value);
+ else
+ g_object_get_property (priv->object, property_name, &cur_value);
interval =
clutter_interval_new_with_values (G_PARAM_SPEC_VALUE_TYPE (pspec),
&cur_value,
&real_value);
- if (!clutter_animation_has_property (animation, pspec->name))
- clutter_animation_bind_property_internal (animation,
+ if (!clutter_animation_has_property (animation, property_name))
+ clutter_animation_bind_property_internal (animation, property_name,
pspec,
interval);
else
- clutter_animation_update_property_internal (animation,
+ clutter_animation_update_property_internal (animation, property_name,
pspec,
interval);
g_value_unset (&cur_value);
}
else
- g_object_set_property (priv->object, property_name, &real_value);
+ {
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ clutter_animatable_set_final_state (CLUTTER_ANIMATABLE (priv->object),
+ animation,
+ property_name,
+ &real_value);
+ else
+ g_object_set_property (priv->object, property_name, &real_value);
+ }
g_value_unset (&real_value);
}
@@ -1719,11 +1789,15 @@ clutter_animation_setupv (ClutterAnimation *animation,
const GValue *values)
{
ClutterAnimationPrivate *priv = animation->priv;
- GObjectClass *klass;
- gint i;
+ ClutterAnimatable *animatable = NULL;
+ GObjectClass *klass = NULL;
gboolean is_fixed = FALSE;
+ gint i;
- klass = G_OBJECT_GET_CLASS (priv->object);
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ animatable = CLUTTER_ANIMATABLE (priv->object);
+ else
+ klass = G_OBJECT_GET_CLASS (priv->object);
for (i = 0; i < n_properties; i++)
{
@@ -1736,8 +1810,14 @@ clutter_animation_setupv (ClutterAnimation *animation,
is_fixed = TRUE;
}
- pspec = g_object_class_find_property (klass, property_name);
- if (!pspec)
+ if (animatable != NULL)
+ pspec = clutter_animatable_find_property (animatable,
+ animation,
+ property_name);
+ else
+ pspec = g_object_class_find_property (klass, property_name);
+
+ if (pspec == NULL)
{
g_warning ("Cannot bind property '%s': objects of type '%s' do "
"not have this property",
@@ -1792,10 +1872,14 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
va_list var_args)
{
ClutterAnimationPrivate *priv = animation->priv;
- GObjectClass *klass;
+ ClutterAnimatable *animatable = NULL;
+ GObjectClass *klass = NULL;
const gchar *property_name;
- klass = G_OBJECT_GET_CLASS (priv->object);
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ animatable = CLUTTER_ANIMATABLE (priv->object);
+ else
+ klass = G_OBJECT_GET_CLASS (priv->object);
property_name = first_property_name;
while (property_name != NULL)
@@ -1827,8 +1911,14 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
is_fixed = TRUE;
}
- pspec = g_object_class_find_property (klass, property_name);
- if (!pspec)
+ if (animatable != NULL)
+ pspec = clutter_animatable_find_property (animatable,
+ animation,
+ property_name);
+ else
+ pspec = g_object_class_find_property (klass, property_name);
+
+ if (pspec == NULL)
{
g_warning ("Cannot bind property '%s': objects of type '%s' do "
"not have this property",
@@ -1899,7 +1989,7 @@ animation_create_for_actor (ClutterActor *actor)
* @actor: a #ClutterActor
* @alpha: a #ClutterAlpha
* @first_property_name: the name of a property
- * @VarArgs: a %NULL terminated list of property names and
+ * @Varargs: a %NULL terminated list of property names and
* property values
*
* Animates the given list of properties of @actor between the current
@@ -1956,7 +2046,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
* @mode: an animation mode logical id
* @timeline: a #ClutterTimeline
* @first_property_name: the name of a property
- * @VarArgs: a %NULL terminated list of property names and
+ * @Varargs: a %NULL terminated list of property names and
* property values
*
* Animates the given list of properties of @actor between the current
@@ -2007,7 +2097,7 @@ clutter_actor_animate_with_timeline (ClutterActor *actor,
* @mode: an animation mode logical id
* @duration: duration of the animation, in milliseconds
* @first_property_name: the name of a property
- * @VarArgs: a %NULL terminated list of property names and
+ * @Varargs: a %NULL terminated list of property names and
* property values
*
* Animates the given list of properties of @actor between the current
diff --git a/clutter/clutter-animator.c b/clutter/clutter-animator.c
index 324570802..0c3287ac5 100644
--- a/clutter/clutter-animator.c
+++ b/clutter/clutter-animator.c
@@ -1150,7 +1150,7 @@ clutter_animator_get_duration (ClutterAnimator *animator)
* @first_mode: the id of the alpha function to use
* @first_progress: at which stage of the animation this value applies; the
* range is a normalized floating point value between 0 and 1
- * @VarArgs: the value first_property_name should have for first_object
+ * @Varargs: the value first_property_name should have for first_object
* at first_progress, followed by more (object, property_name, mode,
* progress, value) tuples, followed by %NULL
*
diff --git a/clutter/clutter-bind-constraint.c b/clutter/clutter-bind-constraint.c
new file mode 100644
index 000000000..583ffd18b
--- /dev/null
+++ b/clutter/clutter-bind-constraint.c
@@ -0,0 +1,337 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+/**
+ * SECTION:clutter-bind-constraint
+ * @Title: ClutterBindConstraint
+ * @Short_Description: A constraint binding the position of an actor
+ *
+ * #ClutterBindConstraint is a #ClutterConstraint that binds the position of
+ * the #ClutterActor to which it is applied to the the position of another
+ * #ClutterActor.
+ *
+ * #ClutterBindConstraint is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-bind-constraint.h"
+
+#include "clutter-constraint.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-private.h"
+
+#define CLUTTER_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass))
+#define CLUTTER_IS_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIND_CONSTRAINT))
+#define CLUTTER_BIND_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass))
+
+typedef struct _ClutterBindConstraintClass ClutterBindConstraintClass;
+
+struct _ClutterBindConstraint
+{
+ ClutterConstraint parent_instance;
+
+ ClutterActor *source;
+ ClutterBindCoordinate coordinate;
+ gfloat offset;
+};
+
+struct _ClutterBindConstraintClass
+{
+ ClutterConstraintClass parent_class;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_SOURCE,
+ PROP_COORDINATE,
+ PROP_OFFSET
+};
+
+G_DEFINE_TYPE (ClutterBindConstraint,
+ clutter_bind_constraint,
+ CLUTTER_TYPE_CONSTRAINT);
+
+static void
+update_actor_position (ClutterBindConstraint *bind)
+{
+ ClutterVertex source_position;
+ ClutterActor *actor;
+
+ if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (bind)))
+ return;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (bind));
+ if (actor == NULL)
+ return;
+
+ source_position.x = clutter_actor_get_x (bind->source);
+ source_position.y = clutter_actor_get_y (bind->source);
+ source_position.z = clutter_actor_get_depth (bind->source);
+
+ switch (bind->coordinate)
+ {
+ case CLUTTER_BIND_X:
+ clutter_actor_set_x (actor, source_position.x + bind->offset);
+ break;
+
+ case CLUTTER_BIND_Y:
+ clutter_actor_set_y (actor, source_position.y + bind->offset);
+ break;
+
+ case CLUTTER_BIND_Z:
+ clutter_actor_set_depth (actor, source_position.z + bind->offset);
+ break;
+ }
+}
+
+static void
+source_position_changed (GObject *gobject,
+ GParamSpec *pspec,
+ ClutterBindConstraint *bind)
+{
+ if (strcmp (pspec->name, "x") == 0 ||
+ strcmp (pspec->name, "y") == 0 ||
+ strcmp (pspec->name, "depth") == 0)
+ {
+ update_actor_position (bind);
+ }
+}
+
+static void
+source_destroyed (ClutterActor *actor,
+ ClutterBindConstraint *bind)
+{
+ bind->source = NULL;
+}
+
+static void
+_clutter_bind_constraint_set_source (ClutterBindConstraint *bind,
+ ClutterActor *source)
+{
+ ClutterActor *old_source = bind->source;
+
+ if (old_source != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (old_source,
+ G_CALLBACK (source_destroyed),
+ bind);
+ g_signal_handlers_disconnect_by_func (old_source,
+ G_CALLBACK (source_position_changed),
+ bind);
+ }
+
+ bind->source = source;
+ g_signal_connect (bind->source, "notify",
+ G_CALLBACK (source_position_changed),
+ bind);
+ g_signal_connect (bind->source, "destroy",
+ G_CALLBACK (source_destroyed),
+ bind);
+
+ update_actor_position (bind);
+
+ g_object_notify (G_OBJECT (bind), "source");
+}
+
+static void
+_clutter_bind_constraint_set_coordinate (ClutterBindConstraint *bind,
+ ClutterBindCoordinate coord)
+{
+ if (bind->coordinate == coord)
+ return;
+
+ bind->coordinate = coord;
+
+ update_actor_position (bind);
+
+ g_object_notify (G_OBJECT (bind), "coordinate");
+}
+
+static void
+_clutter_bind_constraint_set_offset (ClutterBindConstraint *bind,
+ gfloat offset)
+{
+ if (fabs (bind->offset - offset) < 0.00001f)
+ return;
+
+ bind->offset = offset;
+
+ update_actor_position (bind);
+
+ g_object_notify (G_OBJECT (bind), "offset");
+}
+
+static void
+clutter_bind_constraint_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ _clutter_bind_constraint_set_source (bind, g_value_get_object (value));
+ break;
+
+ case PROP_COORDINATE:
+ _clutter_bind_constraint_set_coordinate (bind, g_value_get_enum (value));
+ break;
+
+ case PROP_OFFSET:
+ _clutter_bind_constraint_set_offset (bind, g_value_get_float (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_bind_constraint_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterBindConstraint *bind = CLUTTER_BIND_CONSTRAINT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ g_value_set_object (value, bind->source);
+ break;
+
+ case PROP_COORDINATE:
+ g_value_set_enum (value, bind->coordinate);
+ break;
+
+ case PROP_OFFSET:
+ g_value_set_float (value, bind->offset);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_bind_constraint_class_init (ClutterBindConstraintClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ gobject_class->set_property = clutter_bind_constraint_set_property;
+ gobject_class->get_property = clutter_bind_constraint_get_property;
+
+ /**
+ * ClutterBindConstraint:source:
+ *
+ * The #ClutterActor used as the source for the binding
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("source",
+ "Source",
+ "The source of the binding",
+ CLUTTER_TYPE_ACTOR,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_SOURCE, pspec);
+
+ /**
+ * ClutterBindConstraint:coordinate:
+ *
+ * The coordinate to be bound
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_enum ("coordinate",
+ "Coordinate",
+ "The coordinate to bind",
+ CLUTTER_TYPE_BIND_COORDINATE,
+ CLUTTER_BIND_X,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_COORDINATE, pspec);
+
+ /**
+ * ClutterBindConstraint:offset:
+ *
+ * The offset, in pixels, to be applied to the binding
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_float ("offset",
+ "Offset",
+ "The offset in pixels to apply to the binding",
+ -G_MAXFLOAT, G_MAXFLOAT,
+ 0.0f,
+ CLUTTER_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT);
+ g_object_class_install_property (gobject_class, PROP_OFFSET, pspec);
+}
+
+static void
+clutter_bind_constraint_init (ClutterBindConstraint *self)
+{
+ self->source = NULL;
+ self->coordinate = CLUTTER_BIND_X;
+ self->offset = 0.0f;
+}
+
+/**
+ * clutter_bind_constraint_new:
+ * @source: the #ClutterActor to use as the source of the binding
+ * @coordinate: the coordinate to bind
+ * @offset: the offset to apply to the binding, in pixels
+ *
+ * Creates a new constraint, binding a #ClutterActor's position to
+ * the given @coordinate of the position of @source
+ *
+ * Return value: the newly created #ClutterBindConstraint
+ *
+ * Since: 1.4
+ */
+ClutterConstraint *
+clutter_bind_constraint_new (ClutterActor *source,
+ ClutterBindCoordinate coordinate,
+ gfloat offset)
+{
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (source), NULL);
+
+ return g_object_new (CLUTTER_TYPE_BIND_CONSTRAINT,
+ "source", source,
+ "coordinate", coordinate,
+ "offset", offset,
+ NULL);
+}
diff --git a/clutter/clutter-bind-constraint.h b/clutter/clutter-bind-constraint.h
new file mode 100644
index 000000000..8c713604f
--- /dev/null
+++ b/clutter/clutter-bind-constraint.h
@@ -0,0 +1,74 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_BIND_CONSTRAINT_H__
+#define __CLUTTER_BIND_CONSTRAINT_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_BIND_CONSTRAINT (clutter_bind_constraint_get_type ())
+#define CLUTTER_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraint))
+#define CLUTTER_IS_BIND_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIND_CONSTRAINT))
+
+/**
+ * ClutterBindConstraint:
+ *
+ * ClutterBindConstraint is an opaque structure
+ * whose members cannot be directly accessed
+ *
+ * Since: 1.4
+ */
+typedef struct _ClutterBindConstraint ClutterBindConstraint;
+
+/**
+ * ClutterBindCoordinate:
+ * @CLUTTER_BIND_X: Bind the X coordinate
+ * @CLUTTER_BIND_Y: Bind the Y coordinate
+ * @CLUTTER_BIND_Z: Bind the Z coordinate
+ *
+ * Specifies which coordinate should be used in a binding
+ *
+ * Since: 1.4
+ */
+typedef enum { /*< prefix=CLUTTER_BIND >*/
+ CLUTTER_BIND_X,
+ CLUTTER_BIND_Y,
+ CLUTTER_BIND_Z
+} ClutterBindCoordinate;
+
+GType clutter_bind_constraint_get_type (void) G_GNUC_CONST;
+
+ClutterConstraint *clutter_bind_constraint_new (ClutterActor *source,
+ ClutterBindCoordinate coordinate,
+ gfloat offset);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_BIND_CONSTRAINT_H__ */
diff --git a/clutter/clutter-box-layout.c b/clutter/clutter-box-layout.c
index b4902317b..28730bb5b 100644
--- a/clutter/clutter-box-layout.c
+++ b/clutter/clutter-box-layout.c
@@ -1419,7 +1419,7 @@ clutter_box_layout_get_vertical (ClutterBoxLayout *layout)
/**
* clutter_box_layout_set_homogeneous:
* @layout: a #ClutterBoxLayout
- * @vertical: %TRUE if the layout should be homogeneous
+ * @homogeneous: %TRUE if the layout should be homogeneous
*
* Sets whether the size of @layout children should be
* homogeneous
diff --git a/clutter/clutter-constraint.c b/clutter/clutter-constraint.c
new file mode 100644
index 000000000..49d30c968
--- /dev/null
+++ b/clutter/clutter-constraint.c
@@ -0,0 +1,33 @@
+/**
+ * SECTION:clutter-constraint
+ * @Title: ClutterConstraint
+ * @Short_Description: A constraint on an actor's position or size
+ * @See_Also: #ClutterAction
+ *
+ * #ClutterConstraint is a base abstract class for modifiers of a #ClutterActor
+ * position or size.
+ *
+ * #ClutterConstraint is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-constraint.h"
+
+#include "clutter-actor-meta-private.h"
+
+G_DEFINE_ABSTRACT_TYPE (ClutterConstraint,
+ clutter_constraint,
+ CLUTTER_TYPE_ACTOR_META);
+
+static void
+clutter_constraint_class_init (ClutterConstraintClass *klass)
+{
+}
+
+static void
+clutter_constraint_init (ClutterConstraint *self)
+{
+}
diff --git a/clutter/clutter-constraint.h b/clutter/clutter-constraint.h
new file mode 100644
index 000000000..948670585
--- /dev/null
+++ b/clutter/clutter-constraint.h
@@ -0,0 +1,102 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_CONSTRAINT_H__
+#define __CLUTTER_CONSTRAINT_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_CONSTRAINT (clutter_constraint_get_type ())
+#define CLUTTER_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraint))
+#define CLUTTER_IS_CONSTRAINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CONSTRAINT))
+#define CLUTTER_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass))
+#define CLUTTER_IS_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CONSTRAINT))
+#define CLUTTER_CONSTRAINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CONSTRAINT, ClutterConstraintClass))
+
+typedef struct _ClutterConstraintClass ClutterConstraintClass;
+
+/**
+ * ClutterConstraint:
+ *
+ * The ClutterConstraint structure contains only
+ * private data and should be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterConstraint
+{
+ /*< private >*/
+ ClutterActorMeta parent_instance;
+};
+
+/**
+ * ClutterConstraintClass:
+ *
+ * The ClutterConstraintClass structure contains
+ * only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterConstraintClass
+{
+ /*< private >*/
+ ClutterActorMetaClass parent_class;
+
+ /*< private >*/
+ void (* _clutter_constraint1) (void);
+ void (* _clutter_constraint2) (void);
+ void (* _clutter_constraint3) (void);
+ void (* _clutter_constraint4) (void);
+ void (* _clutter_constraint5) (void);
+ void (* _clutter_constraint6) (void);
+ void (* _clutter_constraint7) (void);
+ void (* _clutter_constraint8) (void);
+};
+
+GType clutter_constraint_get_type (void) G_GNUC_CONST;
+
+/* ClutterActor API */
+void clutter_actor_add_constraint (ClutterActor *self,
+ ClutterConstraint *constraint);
+void clutter_actor_add_constraint_with_name (ClutterActor *self,
+ const gchar *name,
+ ClutterConstraint *constraint);
+void clutter_actor_remove_constraint (ClutterActor *self,
+ ClutterConstraint *constraint);
+void clutter_actor_remove_constraint_by_name (ClutterActor *self,
+ const gchar *name);
+GList * clutter_actor_get_constraints (ClutterActor *self);
+ClutterConstraint *clutter_actor_get_constraint (ClutterActor *self,
+ const gchar *name);
+void clutter_actor_clear_constraints (ClutterActor *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_CONSTRAINT_H__ */
diff --git a/clutter/clutter-drag-action.c b/clutter/clutter-drag-action.c
new file mode 100644
index 000000000..ae51e8104
--- /dev/null
+++ b/clutter/clutter-drag-action.c
@@ -0,0 +1,813 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+/**
+ * SECTION:clutter-drag-action
+ * @Title: ClutterDragAction
+ * @Short_Description: Action enabling dragging on actors
+ *
+ * #ClutterDragAction is a sub-class of #ClutterAction that implements
+ * all the necessary logic for dragging actors.
+ *
+ * The simplest usage of #ClutterDragAction consists in adding it to
+ * a #ClutterActor and connecting to the #ClutterDragAction::drag-motion
+ * signal handler to move the actor; for instance:
+ *
+ * |[
+ * ClutterAction *action = clutter_drag_action_new ();
+ *
+ * g_signal_connect (action, "drag-motion",
+ * G_CALLBACK (on_drag_motion),
+ * NULL);
+ *
+ * clutter_actor_add_action (actor, action);
+ * ]|
+ *
+ * Where the on_drag_motion() signal handler calls clutter_actor_move_by()
+ * using the delta between motion events passed to the handler:
+ *
+ * |[
+ * static void
+ * on_drag_motion (ClutterDragAction *action,
+ * ClutterActor *actor,
+ * gfloat delta_x,
+ * gfloat delta_y,
+ * ClutterModifierType modifiers)
+ * {
+ * clutter_actor_move_by (actor, delta_x, delta_y);
+ * }
+ * ]|
+ *
+ * It is also possible to set another #ClutterActor as the dragged actor
+ * by calling clutter_drag_action_set_drag_handle() from within a handle
+ * of the #ClutterDragAction::drag-begin signal. The drag handle must be
+ * parented and exist between the emission of #ClutterDragAction::drag-begin
+ * and #ClutterDragAction::drag-end.
+ *
+ * #ClutterDragAction is available since Clutter 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-drag-action.h"
+
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+
+struct _ClutterDragActionPrivate
+{
+ ClutterActor *stage;
+
+ gfloat drag_threshold;
+ ClutterActor *drag_handle;
+ ClutterDragAxis drag_axis;
+
+ gulong button_press_id;
+ gulong capture_id;
+
+ gfloat press_x;
+ gfloat press_y;
+ ClutterModifierType press_state;
+ gint press_button;
+
+ gfloat last_motion_x;
+ gfloat last_motion_y;
+
+ gfloat transformed_press_x;
+ gfloat transformed_press_y;
+
+ guint emit_delayed_press : 1;
+ guint in_drag : 1;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_DRAG_THRESHOLD,
+ PROP_DRAG_HANDLE,
+ PROP_DRAG_AXIS
+};
+
+enum
+{
+ DRAG_BEGIN,
+ DRAG_MOTION,
+ DRAG_END,
+
+ LAST_SIGNAL
+};
+
+static guint drag_signals[LAST_SIGNAL] = { 0, };
+
+/* forward declaration */
+static gboolean on_captured_event (ClutterActor *stage,
+ ClutterEvent *event,
+ ClutterDragAction *action);
+
+G_DEFINE_TYPE (ClutterDragAction, clutter_drag_action, CLUTTER_TYPE_ACTION);
+
+static void
+emit_drag_begin (ClutterDragAction *action,
+ ClutterActor *actor,
+ ClutterEvent *event)
+{
+ ClutterDragActionPrivate *priv = action->priv;
+
+ g_signal_emit (action, drag_signals[DRAG_BEGIN], 0,
+ actor,
+ priv->press_x, priv->press_y,
+ priv->press_button,
+ priv->press_state);
+}
+
+static void
+emit_drag_motion (ClutterDragAction *action,
+ ClutterActor *actor,
+ ClutterEvent *event)
+{
+ ClutterDragActionPrivate *priv = action->priv;
+ ClutterActor *drag_handle = NULL;
+ gfloat delta_x, delta_y;
+ gfloat motion_x, motion_y;
+
+ clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y);
+
+ if (priv->drag_handle != NULL && !priv->emit_delayed_press)
+ drag_handle = priv->drag_handle;
+ else
+ drag_handle = actor;
+
+ motion_x = motion_y = 0.0f;
+ clutter_actor_transform_stage_point (drag_handle,
+ priv->last_motion_x,
+ priv->last_motion_y,
+ &motion_x, &motion_y);
+
+ delta_x = delta_y = 0.0f;
+
+ switch (priv->drag_axis)
+ {
+ case CLUTTER_DRAG_AXIS_NONE:
+ delta_x = motion_x - priv->transformed_press_x;
+ delta_y = motion_y - priv->transformed_press_y;
+ break;
+
+ case CLUTTER_DRAG_X_AXIS:
+ delta_x = motion_x - priv->transformed_press_x;
+ break;
+
+ case CLUTTER_DRAG_Y_AXIS:
+ delta_y = motion_y - priv->transformed_press_y;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+
+ if (priv->emit_delayed_press)
+ {
+ if (ABS (delta_x) >= priv->drag_threshold ||
+ ABS (delta_y) >= priv->drag_threshold)
+ {
+ priv->emit_delayed_press = FALSE;
+
+ emit_drag_begin (action, actor, NULL);
+ }
+ else
+ return;
+ }
+
+ g_signal_emit (action, drag_signals[DRAG_MOTION], 0,
+ actor,
+ delta_x, delta_y);
+}
+
+static void
+emit_drag_end (ClutterDragAction *action,
+ ClutterActor *actor,
+ ClutterEvent *event)
+{
+ ClutterDragActionPrivate *priv = action->priv;
+
+ clutter_event_get_coords (event, &priv->last_motion_x, &priv->last_motion_y);
+
+ /* we might not have emitted ::drag-begin yet */
+ if (!priv->emit_delayed_press)
+ g_signal_emit (action, drag_signals[DRAG_END], 0,
+ actor,
+ priv->last_motion_x, priv->last_motion_y,
+ clutter_event_get_button (event),
+ clutter_event_get_state (event));
+
+ /* disconnect the capture */
+ if (priv->capture_id != 0)
+ {
+ g_signal_handler_disconnect (priv->stage, priv->capture_id);
+ priv->capture_id = 0;
+ }
+
+ priv->in_drag = FALSE;
+}
+
+static gboolean
+on_captured_event (ClutterActor *stage,
+ ClutterEvent *event,
+ ClutterDragAction *action)
+{
+ ClutterDragActionPrivate *priv = action->priv;
+ ClutterActor *actor;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
+
+ if (!priv->in_drag)
+ return FALSE;
+
+ switch (clutter_event_type (event))
+ {
+ case CLUTTER_MOTION:
+ {
+ ClutterModifierType mods = clutter_event_get_state (event);
+
+ /* we might miss a button-release event in case of grabs,
+ * so we need to check whether the button is still down
+ * during a motion event
+ */
+ if (mods & CLUTTER_BUTTON1_MASK)
+ emit_drag_motion (action, actor, event);
+ else
+ emit_drag_end (action, actor, event);
+ }
+ break;
+
+ case CLUTTER_BUTTON_RELEASE:
+ if (priv->in_drag)
+ emit_drag_end (action, actor, event);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_button_press (ClutterActor *actor,
+ ClutterEvent *event,
+ ClutterDragAction *action)
+{
+ ClutterDragActionPrivate *priv = action->priv;
+
+ if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
+ return FALSE;
+
+ if (priv->stage == NULL)
+ priv->stage = clutter_actor_get_stage (actor);
+
+ clutter_event_get_coords (event, &priv->press_x, &priv->press_y);
+ priv->press_button = clutter_event_get_button (event);
+ priv->press_state = clutter_event_get_state (event);
+
+ priv->last_motion_x = priv->press_x;
+ priv->last_motion_y = priv->press_y;
+
+ priv->transformed_press_x = priv->press_x;
+ priv->transformed_press_y = priv->press_y;
+ clutter_actor_transform_stage_point (actor, priv->press_x, priv->press_y,
+ &priv->transformed_press_x,
+ &priv->transformed_press_y);
+
+ if (priv->drag_threshold == 0)
+ emit_drag_begin (action, actor, event);
+ else
+ priv->emit_delayed_press = TRUE;
+
+ priv->in_drag = TRUE;
+ priv->capture_id = g_signal_connect_after (priv->stage, "captured-event",
+ G_CALLBACK (on_captured_event),
+ action);
+
+ return FALSE;
+}
+
+static void
+clutter_drag_action_set_actor (ClutterActorMeta *meta,
+ ClutterActor *actor)
+{
+ ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (meta)->priv;
+
+ if (priv->button_press_id != 0)
+ {
+ ClutterActor *old_actor;
+
+ old_actor = clutter_actor_meta_get_actor (meta);
+
+ g_signal_handler_disconnect (old_actor, priv->button_press_id);
+
+ if (priv->capture_id != 0)
+ g_signal_handler_disconnect (old_actor, priv->capture_id);
+
+ priv->button_press_id = 0;
+ priv->capture_id = 0;
+
+ priv->stage = NULL;
+ }
+
+ if (actor != NULL)
+ priv->button_press_id = g_signal_connect (actor, "button-press-event",
+ G_CALLBACK (on_button_press),
+ meta);
+
+ CLUTTER_ACTOR_META_CLASS (clutter_drag_action_parent_class)->set_actor (meta, actor);
+}
+
+static void
+clutter_drag_action_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterDragAction *action = CLUTTER_DRAG_ACTION (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_DRAG_THRESHOLD:
+ clutter_drag_action_set_drag_threshold (action, g_value_get_uint (value));
+ break;
+
+ case PROP_DRAG_HANDLE:
+ clutter_drag_action_set_drag_handle (action, g_value_get_object (value));
+ break;
+
+ case PROP_DRAG_AXIS:
+ clutter_drag_action_set_drag_axis (action, g_value_get_enum (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+clutter_drag_action_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_DRAG_THRESHOLD:
+ g_value_set_uint (value, priv->drag_threshold);
+ break;
+
+ case PROP_DRAG_HANDLE:
+ g_value_set_object (value, priv->drag_handle);
+ break;
+
+ case PROP_DRAG_AXIS:
+ g_value_set_enum (value, priv->drag_axis);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+clutter_drag_action_dispose (GObject *gobject)
+{
+ ClutterDragActionPrivate *priv = CLUTTER_DRAG_ACTION (gobject)->priv;
+
+ if (priv->capture_id != 0)
+ {
+ if (priv->stage != NULL)
+ g_signal_handler_disconnect (priv->stage, priv->capture_id);
+
+ priv->capture_id = 0;
+ priv->stage = NULL;
+ }
+
+ if (priv->button_press_id != 0)
+ {
+ ClutterActor *actor;
+
+ actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject));
+ g_signal_handler_disconnect (actor, priv->button_press_id);
+ priv->button_press_id = 0;
+ }
+
+ G_OBJECT_CLASS (clutter_drag_action_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_drag_action_class_init (ClutterDragActionClass *klass)
+{
+ ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterDragActionPrivate));
+
+ gobject_class->set_property = clutter_drag_action_set_property;
+ gobject_class->get_property = clutter_drag_action_get_property;
+ gobject_class->dispose = clutter_drag_action_dispose;
+
+ meta_class->set_actor = clutter_drag_action_set_actor;
+
+ /**
+ * ClutterDragAction:drag-threshold:
+ *
+ * The threshold, in pixels, that begins a drag action
+ *
+ * When set to a non-zero value, #ClutterDragAction will only emit
+ * #ClutterDragAction::drag-begin if the pointer has moved at least
+ * of the given amount of pixels since the button press event
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_uint ("drag-threshold",
+ "Drag Threshold",
+ "The amount of pixels required to start "
+ "dragging",
+ 0, G_MAXUINT,
+ 0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_DRAG_THRESHOLD, pspec);
+
+ /**
+ * ClutterDragAction:drag-handle:
+ *
+ * The #ClutterActor that is effectively being dragged
+ *
+ * A #ClutterDragActor will, be default, use the #ClutterActor that
+ * has been attached to the action; it is possible to create a
+ * separate #ClutterActor and use it instead.
+ *
+ * Setting this property has no effect on the #ClutterActor argument
+ * passed to the #ClutterDragAction signals
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_object ("drag-handle",
+ "Drag Handle",
+ "The actor that is being dragged",
+ CLUTTER_TYPE_ACTOR,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_DRAG_HANDLE, pspec);
+
+ /**
+ * ClutterDragAction:drag-axis:
+ *
+ * Constraints the dragging action to the specified axis
+ *
+ * Since: 1.4
+ */
+ pspec = g_param_spec_enum ("drag-axis",
+ "Drag Axis",
+ "Constraints the dragging to an axis",
+ CLUTTER_TYPE_DRAG_AXIS,
+ CLUTTER_DRAG_AXIS_NONE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_DRAG_AXIS, pspec);
+
+ /**
+ * ClutterDragAction::drag-begin:
+ * @action: the #ClutterDragAction that emitted the signal
+ * @actor: the #ClutterActor attached to the action
+ * @event_x: the X coordinate (in stage space) of the press event
+ * @event_y: the Y coordinate (in stage space) of the press event
+ * @button: the button of the press event
+ * @modifiers: the modifiers of the press event
+ *
+ * The ::drag-begin signal is emitted when the #ClutterDragAction
+ * starts the dragging
+ *
+ * The emission of this signal can be delayed by using the
+ * #ClutterDragAction:drag-threshold property
+ *
+ * Since: 1.4
+ */
+ drag_signals[DRAG_BEGIN] =
+ g_signal_new (I_("drag-begin"),
+ CLUTTER_TYPE_DRAG_ACTION,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterDragActionClass, drag_begin),
+ NULL, NULL,
+ clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_INT_FLAGS,
+ G_TYPE_NONE, 5,
+ CLUTTER_TYPE_ACTOR,
+ G_TYPE_FLOAT,
+ G_TYPE_FLOAT,
+ G_TYPE_INT,
+ CLUTTER_TYPE_MODIFIER_TYPE);
+
+ /**
+ * ClutterDragAction::drag-motion
+ * @action: the #ClutterDragAction that emitted the signal
+ * @actor: the #ClutterActor attached to the action
+ * @delta_x: the X component of the distance between the press event
+ * that began the dragging and the current position of the pointer,
+ * as of the latest motion event
+ * @delta_y: the Y component of the distance between the press event
+ * that began the dragging and the current position of the pointer,
+ * as of the latest motion event
+ * @modifiers: the modifiers of the latest motion event
+ *
+ * The ::drag-motion signal is emitted for each motion event after
+ * the #ClutterDragAction::drag-begin signal has been emitted.
+ *
+ * The components of the distance between the press event and the
+ * latest motion event are computed in the actor's coordinate space,
+ * to take into account eventual transformations. If you want the
+ * stage coordinates of the latest motion event you can use
+ * clutter_drag_action_get_motion_coords().
+ *
+ * Since: 1.4
+ */
+ drag_signals[DRAG_MOTION] =
+ g_signal_new (I_("drag-motion"),
+ CLUTTER_TYPE_DRAG_ACTION,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterDragActionClass, drag_motion),
+ NULL, NULL,
+ clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
+ G_TYPE_NONE, 3,
+ CLUTTER_TYPE_ACTOR,
+ G_TYPE_FLOAT,
+ G_TYPE_FLOAT);
+
+ /**
+ * ClutterDragAction::drag-end:
+ * @action: the #ClutterDragAction that emitted the signal
+ * @actor: the #ClutterActor attached to the action
+ * @event_x: the X coordinate (in stage space) of the release event
+ * @event_y: the Y coordinate (in stage space) of the release event
+ * @button: the button of the release event
+ * @modifiers: the modifiers of the release event
+ *
+ * The ::drag-end signal is emitted at the end of the dragging,
+ * when the pointer button's is released
+ *
+ * This signal is emitted if and only if the #ClutterDragAction::drag-begin
+ * signal has been emitted first
+ *
+ * Since: 1.4
+ */
+ drag_signals[DRAG_END] =
+ g_signal_new (I_("drag-end"),
+ CLUTTER_TYPE_DRAG_ACTION,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterDragActionClass, drag_end),
+ NULL, NULL,
+ clutter_marshal_VOID__OBJECT_FLOAT_FLOAT_INT_FLAGS,
+ G_TYPE_NONE, 5,
+ CLUTTER_TYPE_ACTOR,
+ G_TYPE_FLOAT,
+ G_TYPE_FLOAT,
+ G_TYPE_INT,
+ CLUTTER_TYPE_MODIFIER_TYPE);
+}
+
+static void
+clutter_drag_action_init (ClutterDragAction *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_DRAG_ACTION,
+ ClutterDragActionPrivate);
+}
+
+/**
+ * clutter_drag_action_new:
+ *
+ * Creates a new #ClutterDragAction instance
+ *
+ * Return value: the newly created #ClutterDragAction
+ *
+ * Since: 1.4
+ */
+ClutterAction *
+clutter_drag_action_new (void)
+{
+ return g_object_new (CLUTTER_TYPE_DRAG_ACTION, NULL);
+}
+
+/**
+ * clutter_drag_action_set_drag_threshold:
+ * @action: a #ClutterDragAction
+ * @threshold: a distance, in pixels
+ *
+ * Sets the drag threshold that must be cleared by the pointer
+ * before @action can begin the dragging
+ *
+ * Since: 1.4
+ */
+void
+clutter_drag_action_set_drag_threshold (ClutterDragAction *action,
+ guint threshold)
+{
+ ClutterDragActionPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
+
+ priv = action->priv;
+
+ if (priv->drag_threshold == threshold)
+ return;
+
+ priv->drag_threshold = threshold;
+
+ g_object_notify (G_OBJECT (action), "drag-threshold");
+}
+
+/**
+ * clutter_drag_action_get_drag_threshold:
+ * @action: a #ClutterDragAction
+ *
+ * Retrieves the value set by clutter_drag_action_set_drag_threshold()
+ *
+ * Return value: the drag threshold value, in pixels
+ *
+ * Since: 1.4
+ */
+guint
+clutter_drag_action_get_drag_threshold (ClutterDragAction *action)
+{
+ g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), 0);
+
+ return action->priv->drag_threshold;
+}
+
+/**
+ * clutter_drag_action_set_drag_handle:
+ * @action: a #ClutterDragHandle
+ * @handle: a #ClutterActor
+ *
+ * Sets the actor to be used as the drag handle
+ *
+ * Since: 1.4
+ */
+void
+clutter_drag_action_set_drag_handle (ClutterDragAction *action,
+ ClutterActor *handle)
+{
+ ClutterDragActionPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
+ g_return_if_fail (CLUTTER_IS_ACTOR (handle));
+
+ priv = action->priv;
+
+ if (priv->drag_handle == handle)
+ return;
+
+ priv->drag_handle = handle;
+
+ g_object_notify (G_OBJECT (action), "drag-handle");
+}
+
+/**
+ * clutter_drag_action_get_drag_handle:
+ * @action: a #ClutterDragAction
+ *
+ * Retrieves the drag handle set by clutter_drag_action_set_drag_handle()
+ *
+ * Return value: (transfer none): a #ClutterActor, used as the drag
+ * handle, or %NULL if none was set
+ *
+ * Since: 1.4
+ */
+ClutterActor *
+clutter_drag_action_get_drag_handle (ClutterDragAction *action)
+{
+ g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action), NULL);
+
+ return action->priv->drag_handle;
+}
+
+/**
+ * clutter_drag_action_set_drag_axis:
+ * @action: a #ClutterDragAction
+ * @axis: the axis to constraint the dragging to
+ *
+ * Restricts the dragging action to a specific axis
+ *
+ * Since: 1.4
+ */
+void
+clutter_drag_action_set_drag_axis (ClutterDragAction *action,
+ ClutterDragAxis axis)
+{
+ ClutterDragActionPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
+ g_return_if_fail (axis >= CLUTTER_DRAG_AXIS_NONE &&
+ axis <= CLUTTER_DRAG_Y_AXIS);
+
+ priv = action->priv;
+
+ if (priv->drag_axis == axis)
+ return;
+
+ priv->drag_axis = axis;
+
+ g_object_notify (G_OBJECT (action), "drag-axis");
+}
+
+/**
+ * clutter_drag_action_get_drag_axis:
+ * @action: a #ClutterDragAction
+ *
+ * Retrieves the axis constraint set by clutter_drag_action_set_drag_axis()
+ *
+ * Return value: the axis constraint
+ *
+ * Since: 1.4
+ */
+ClutterDragAxis
+clutter_drag_action_get_drag_axis (ClutterDragAction *action)
+{
+ g_return_val_if_fail (CLUTTER_IS_DRAG_ACTION (action),
+ CLUTTER_DRAG_AXIS_NONE);
+
+ return action->priv->drag_axis;
+}
+
+/**
+ * clutter_drag_action_get_press_coords:
+ * @action: a #ClutterDragAction
+ * @press_x: (out): return location for the press event's X coordinate
+ * @press_y: (out): return location for the press event's Y coordinate
+ *
+ * Retrieves the coordinates, in stage space, of the press event
+ * that started the dragging
+ *
+ * Since: 1.4
+ */
+void
+clutter_drag_action_get_press_coords (ClutterDragAction *action,
+ gfloat *press_x,
+ gfloat *press_y)
+{
+ g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
+
+ if (press_x)
+ *press_x = action->priv->press_x;
+
+ if (press_y)
+ *press_y = action->priv->press_y;
+}
+
+/**
+ * clutter_drag_action_get_motion_coords:
+ * @action: a #ClutterDragAction
+ * @motion_x: (out): return location for the latest motion
+ * event's X coordinate
+ * @motion_y: (out): return location for the latest motion
+ * event's Y coordinate
+ *
+ * Retrieves the coordinates, in stage space, of the latest motion
+ * event during the dragging
+ *
+ * Since: 1.4
+ */
+void
+clutter_drag_action_get_motion_coords (ClutterDragAction *action,
+ gfloat *motion_x,
+ gfloat *motion_y)
+{
+ g_return_if_fail (CLUTTER_IS_DRAG_ACTION (action));
+
+ if (motion_x)
+ *motion_x = action->priv->last_motion_x;
+
+ if (motion_y)
+ *motion_y = action->priv->last_motion_y;
+}
diff --git a/clutter/clutter-drag-action.h b/clutter/clutter-drag-action.h
new file mode 100644
index 000000000..78290dcf5
--- /dev/null
+++ b/clutter/clutter-drag-action.h
@@ -0,0 +1,148 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 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 .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_DRAG_ACTION_H__
+#define __CLUTTER_DRAG_ACTION_H__
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DRAG_ACTION (clutter_drag_action_get_type ())
+#define CLUTTER_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragAction))
+#define CLUTTER_IS_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAG_ACTION))
+#define CLUTTER_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
+#define CLUTTER_IS_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAG_ACTION))
+#define CLUTTER_DRAG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
+
+typedef struct _ClutterDragAction ClutterDragAction;
+typedef struct _ClutterDragActionPrivate ClutterDragActionPrivate;
+typedef struct _ClutterDragActionClass ClutterDragActionClass;
+
+/**
+ * ClutterDragAxis:
+ * @CLUTTER_DRAG_AXIS_NONE: No constraint
+ * @CLUTTER_DRAG_X_AXIS: Set a constraint on the X axis
+ * @CLUTTER_DRAG_Y_AXIS: Set a constraint on the Y axis
+ *
+ * The axis of the constraint that should be applied on the
+ * dragging action
+ *
+ * Since: 1.4
+ */
+typedef enum { /*< prefix=CLUTTER_DRAG >*/
+ CLUTTER_DRAG_AXIS_NONE = 0,
+
+ CLUTTER_DRAG_X_AXIS,
+ CLUTTER_DRAG_Y_AXIS
+} ClutterDragAxis;
+
+/**
+ * ClutterDragAction:
+ *
+ * The ClutterDragAction structure contains only
+ * private data and should be accessed using the provided API
+ *
+ * Since: 1.4
+ */
+struct _ClutterDragAction
+{
+ /*< private >*/
+ ClutterAction parent_instance;
+
+ ClutterDragActionPrivate *priv;
+};
+
+/**
+ * ClutterDragActionClass:
+ * @drag_begin: class handler of the #ClutterDragAction::drag-begin signal
+ * @drag_motion: class handler of the #ClutterDragAction::drag-motion signal
+ * @drag_end: class handler of the #ClutterDragAction::drag-end signal
+ *
+ * The ClutterDragActionClass structure contains
+ * only private data
+ *
+ * Since: 1.4
+ */
+struct _ClutterDragActionClass
+{
+ /*< private >*/
+ ClutterActionClass parent_class;
+
+ /*< public >*/
+ void (* drag_begin) (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ gint button,
+ ClutterModifierType modifiers);
+ void (* drag_motion) (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat delta_x,
+ gfloat delta_y,
+ ClutterModifierType modifiers);
+ void (* drag_end) (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ gint button,
+ ClutterModifierType modifiers);
+
+ /*< private >*/
+ void (* _clutter_drag_action1) (void);
+ void (* _clutter_drag_action2) (void);
+ void (* _clutter_drag_action3) (void);
+ void (* _clutter_drag_action4) (void);
+ void (* _clutter_drag_action5) (void);
+};
+
+GType clutter_drag_action_get_type (void) G_GNUC_CONST;
+
+ClutterAction * clutter_drag_action_new (void);
+
+void clutter_drag_action_set_drag_threshold (ClutterDragAction *action,
+ guint threshold);
+guint clutter_drag_action_get_drag_threshold (ClutterDragAction *action);
+void clutter_drag_action_set_drag_handle (ClutterDragAction *action,
+ ClutterActor *handle);
+ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action);
+void clutter_drag_action_set_drag_axis (ClutterDragAction *action,
+ ClutterDragAxis axis);
+ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action);
+
+void clutter_drag_action_get_press_coords (ClutterDragAction *action,
+ gfloat *press_x,
+ gfloat *press_y);
+void clutter_drag_action_get_motion_coords (ClutterDragAction *action,
+ gfloat *motion_x,
+ gfloat *motion_y);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DRAG_ACTION_H__ */
diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h
index f0dc8a357..d5e641b6b 100644
--- a/clutter/clutter-event.h
+++ b/clutter/clutter-event.h
@@ -417,7 +417,6 @@ struct _ClutterStageStateEvent
/**
* ClutterEvent:
- * @type: event type
*
* Generic event wrapper.
*
@@ -425,6 +424,7 @@ struct _ClutterStageStateEvent
*/
union _ClutterEvent
{
+ /*< private >*/
ClutterEventType type;
ClutterAnyEvent any;
diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list
index 8296f9add..0ad57424f 100644
--- a/clutter/clutter-marshal.list
+++ b/clutter/clutter-marshal.list
@@ -10,6 +10,8 @@ VOID:INT,INT
VOID:FLOAT,FLOAT
VOID:INT,INT,INT,INT
VOID:OBJECT
+VOID:OBJECT,FLOAT,FLOAT
+VOID:OBJECT,FLOAT,FLOAT,INT,FLAGS
VOID:OBJECT,OBJECT,PARAM
VOID:OBJECT,POINTER
VOID:POINTER
diff --git a/clutter/clutter-media.h b/clutter/clutter-media.h
index a1a768818..7471940d4 100644
--- a/clutter/clutter-media.h
+++ b/clutter/clutter-media.h
@@ -65,6 +65,7 @@ struct _ClutterMediaIface
/*< private >*/
GTypeInterface base_iface;
+ /*< public >*/
/* signals */
void (* eos) (ClutterMedia *media);
void (* error) (ClutterMedia *media,
diff --git a/clutter/clutter-stage-manager.h b/clutter/clutter-stage-manager.h
index 09a334c14..6cb9c5171 100644
--- a/clutter/clutter-stage-manager.h
+++ b/clutter/clutter-stage-manager.h
@@ -53,10 +53,6 @@ typedef struct _ClutterStageManagerClass ClutterStageManagerClass;
/**
* ClutterStageManagerClass:
- * @stage_added: class handler for the #ClutterStageManager::stage-added
- * signal
- * @stage_removed: class handler for the #ClutterStageManager::stage-removed
- * signal
*
* The #ClutterStageManagerClass structure contains only private data
* and should be accessed using the provided API
diff --git a/clutter/clutter-types.h b/clutter/clutter-types.h
index 72090fa2a..9d53ea9a0 100644
--- a/clutter/clutter-types.h
+++ b/clutter/clutter-types.h
@@ -40,12 +40,18 @@ G_BEGIN_DECLS
/* Forward delarations to avoid header catch 22's */
typedef struct _ClutterActor ClutterActor;
+
typedef struct _ClutterStage ClutterStage;
typedef struct _ClutterContainer ClutterContainer; /* dummy */
typedef struct _ClutterChildMeta ClutterChildMeta;
typedef struct _ClutterLayoutMeta ClutterLayoutMeta;
+typedef struct _ClutterActorMeta ClutterActorMeta;
+
typedef struct _ClutterAnimator ClutterAnimator;
+typedef struct _ClutterAction ClutterAction;
+typedef struct _ClutterConstraint ClutterConstraint;
+
typedef union _ClutterEvent ClutterEvent;
/**
diff --git a/clutter/clutter.h b/clutter/clutter.h
index f56876173..49c3dabe3 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -30,7 +30,10 @@
#include "clutter-deprecated.h"
+#include "clutter-action.h"
#include "clutter-actor.h"
+#include "clutter-actor-meta.h"
+#include "clutter-align-constraint.h"
#include "clutter-alpha.h"
#include "clutter-animatable.h"
#include "clutter-animation.h"
@@ -43,6 +46,7 @@
#include "clutter-behaviour-path.h"
#include "clutter-behaviour-rotate.h"
#include "clutter-behaviour-scale.h"
+#include "clutter-bind-constraint.h"
#include "clutter-binding-pool.h"
#include "clutter-bin-layout.h"
#include "clutter-box.h"
@@ -51,8 +55,10 @@
#include "clutter-child-meta.h"
#include "clutter-clone.h"
#include "clutter-color.h"
+#include "clutter-constraint.h"
#include "clutter-container.h"
#include "clutter-device-manager.h"
+#include "clutter-drag-action.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-fixed-layout.h"
diff --git a/clutter/json/json-array.c b/clutter/json/json-array.c
index 16f36a4b0..83e2e0245 100644
--- a/clutter/json/json-array.c
+++ b/clutter/json/json-array.c
@@ -27,7 +27,7 @@
#include "json-types-private.h"
-/**
+/*
* SECTION:json-array
* @short_description: a JSON array representation
*
@@ -57,7 +57,7 @@ json_array_get_type (void)
return array_type;
}
-/**
+/*
* json_array_new:
*
* Creates a new #JsonArray.
@@ -77,7 +77,7 @@ json_array_new (void)
return array;
}
-/**
+/*
* json_array_sized_new:
* @n_elements: number of slots to pre-allocate
*
@@ -98,7 +98,7 @@ json_array_sized_new (guint n_elements)
return array;
}
-/**
+/*
* json_array_ref:
* @array: a #JsonArray
*
@@ -118,7 +118,7 @@ json_array_ref (JsonArray *array)
return array;
}
-/**
+/*
* json_array_unref:
* @array: a #JsonArray
*
@@ -151,7 +151,7 @@ json_array_unref (JsonArray *array)
}
}
-/**
+/*
* json_array_get_elements:
* @array: a #JsonArray
*
@@ -178,7 +178,7 @@ json_array_get_elements (JsonArray *array)
return g_list_reverse (retval);
}
-/**
+/*
* json_array_dup_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -207,7 +207,7 @@ json_array_dup_element (JsonArray *array,
return json_node_copy (retval);
}
-/**
+/*
* json_array_get_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -227,7 +227,7 @@ json_array_get_element (JsonArray *array,
return g_ptr_array_index (array->elements, index_);
}
-/**
+/*
* json_array_get_int_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -257,7 +257,7 @@ json_array_get_int_element (JsonArray *array,
return json_node_get_int (node);
}
-/**
+/*
* json_array_get_double_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -287,7 +287,7 @@ json_array_get_double_element (JsonArray *array,
return json_node_get_double (node);
}
-/**
+/*
* json_array_get_boolean_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -317,7 +317,7 @@ json_array_get_boolean_element (JsonArray *array,
return json_node_get_boolean (node);
}
-/**
+/*
* json_array_get_string_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -348,7 +348,7 @@ json_array_get_string_element (JsonArray *array,
return json_node_get_string (node);
}
-/**
+/*
* json_array_get_null_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -376,7 +376,7 @@ json_array_get_null_element (JsonArray *array,
return JSON_NODE_TYPE (node) == JSON_NODE_NULL;
}
-/**
+/*
* json_array_get_array_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -406,7 +406,7 @@ json_array_get_array_element (JsonArray *array,
return json_node_get_array (node);
}
-/**
+/*
* json_array_get_object_element:
* @array: a #JsonArray
* @index_: the index of the element to retrieve
@@ -436,7 +436,7 @@ json_array_get_object_element (JsonArray *array,
return json_node_get_object (node);
}
-/**
+/*
* json_array_get_length:
* @array: a #JsonArray
*
@@ -452,7 +452,7 @@ json_array_get_length (JsonArray *array)
return array->elements->len;
}
-/**
+/*
* json_array_add_element:
* @array: a #JsonArray
* @node: a #JsonNode
@@ -470,7 +470,7 @@ json_array_add_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_int_element:
* @array: a #JsonArray
* @value: an integer value
@@ -495,7 +495,7 @@ json_array_add_int_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_double_element:
* @array: a #JsonArray
* @value: a floating point value
@@ -520,7 +520,7 @@ json_array_add_double_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_boolean_element:
* @array: a #JsonArray
* @value: a boolean value
@@ -545,7 +545,7 @@ json_array_add_boolean_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_string_element:
* @array: a #JsonArray
* @value: a string value
@@ -571,7 +571,7 @@ json_array_add_string_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_null_element:
* @array: a #JsonArray
*
@@ -593,7 +593,7 @@ json_array_add_null_element (JsonArray *array)
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_array_element:
* @array: a #JsonArray
* @value: a #JsonArray
@@ -620,7 +620,7 @@ json_array_add_array_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_add_object_element:
* @array: a #JsonArray
* @value: a #JsonObject
@@ -647,7 +647,7 @@ json_array_add_object_element (JsonArray *array,
g_ptr_array_add (array->elements, node);
}
-/**
+/*
* json_array_remove_element:
* @array: a #JsonArray
* @index_: the position of the element to be removed
@@ -665,7 +665,7 @@ json_array_remove_element (JsonArray *array,
json_node_free (g_ptr_array_remove_index (array->elements, index_));
}
-/**
+/*
* json_array_foreach_element:
* @array: a #JsonArray
* @func: the function to be called on each element
diff --git a/clutter/json/json-generator.c b/clutter/json/json-generator.c
index c77830e61..0766df34b 100644
--- a/clutter/json/json-generator.c
+++ b/clutter/json/json-generator.c
@@ -21,7 +21,7 @@
* Emmanuele Bassi
*/
-/**
+/*
* SECTION:json-generator
* @short_description: Generates JSON data streams
*
@@ -191,7 +191,7 @@ json_generator_class_init (JsonGeneratorClass *klass)
gobject_class->get_property = json_generator_get_property;
gobject_class->finalize = json_generator_finalize;
- /**
+ /*
* JsonGenerator:pretty:
*
* Whether the output should be "pretty-printed", with indentation and
@@ -205,7 +205,7 @@ json_generator_class_init (JsonGeneratorClass *klass)
"Pretty-print the output",
FALSE,
G_PARAM_READWRITE));
- /**
+ /*
* JsonGenerator:indent:
*
* Number of spaces to be used to indent when pretty printing.
@@ -218,7 +218,7 @@ json_generator_class_init (JsonGeneratorClass *klass)
0, G_MAXUINT,
2,
G_PARAM_READWRITE));
- /**
+ /*
* JsonGenerator:root:
*
* The root #JsonNode to be used when constructing a JSON data
@@ -233,7 +233,7 @@ json_generator_class_init (JsonGeneratorClass *klass)
"Root of the JSON data tree",
JSON_TYPE_NODE,
G_PARAM_READWRITE));
- /**
+ /*
* JsonGenerator:indent-char:
*
* The character that should be used when indenting in pretty print.
@@ -519,7 +519,7 @@ dump_object (JsonGenerator *generator,
return g_string_free (buffer, FALSE);
}
-/**
+/*
* json_generator_new:
*
* Creates a new #JsonGenerator. You can use this object to generate a
@@ -534,7 +534,7 @@ json_generator_new (void)
return g_object_new (JSON_TYPE_GENERATOR, NULL);
}
-/**
+/*
* json_generator_to_data:
* @generator: a #JsonGenerator
* @length: (out): return location for the length of the returned
@@ -588,7 +588,7 @@ json_generator_to_data (JsonGenerator *generator,
return retval;
}
-/**
+/*
* json_generator_to_file:
* @generator: a #JsonGenerator
* @filename: path to the target file
@@ -618,7 +618,7 @@ json_generator_to_file (JsonGenerator *generator,
return retval;
}
-/**
+/*
* json_generator_set_root:
* @generator: a #JsonGenerator
* @node: a #JsonNode
diff --git a/clutter/json/json-node.c b/clutter/json/json-node.c
index e1e457a7d..a56fc7493 100644
--- a/clutter/json/json-node.c
+++ b/clutter/json/json-node.c
@@ -29,7 +29,7 @@
#include "json-types-private.h"
-/**
+/*
* SECTION:json-node
* @short_description: Node in a JSON object model
*
@@ -61,7 +61,7 @@ json_node_get_type (void)
return node_type;
}
-/**
+/*
* json_node_get_value_type:
* @node: a #JsonNode
*
@@ -96,7 +96,7 @@ json_node_get_value_type (JsonNode *node)
}
}
-/**
+/*
* json_node_new:
* @type: a #JsonNodeType
*
@@ -118,7 +118,7 @@ json_node_new (JsonNodeType type)
return data;
}
-/**
+/*
* json_node_copy:
* @node: a #JsonNode
*
@@ -167,7 +167,7 @@ json_node_copy (JsonNode *node)
return copy;
}
-/**
+/*
* json_node_set_object:
* @node: a #JsonNode
* @object: a #JsonObject
@@ -190,7 +190,7 @@ json_node_set_object (JsonNode *node,
node->data.object = NULL;
}
-/**
+/*
* json_node_take_object:
* @node: a #JsonNode
* @object: a #JsonObject
@@ -214,7 +214,7 @@ json_node_take_object (JsonNode *node,
node->data.object = object;
}
-/**
+/*
* json_node_get_object:
* @node: a #JsonNode
*
@@ -231,7 +231,7 @@ json_node_get_object (JsonNode *node)
return node->data.object;
}
-/**
+/*
* json_node_dup_object:
* @node: a #JsonNode
*
@@ -252,7 +252,7 @@ json_node_dup_object (JsonNode *node)
return NULL;
}
-/**
+/*
* json_node_set_array:
* @node: a #JsonNode
* @array: a #JsonArray
@@ -275,7 +275,7 @@ json_node_set_array (JsonNode *node,
node->data.array = NULL;
}
-/**
+/*
* json_node_take_array:
* @node: a #JsonNode
* @array: a #JsonArray
@@ -299,7 +299,7 @@ json_node_take_array (JsonNode *node,
node->data.array = array;
}
-/**
+/*
* json_node_get_array:
* @node: a #JsonNode
*
@@ -316,7 +316,7 @@ json_node_get_array (JsonNode *node)
return node->data.array;
}
-/**
+/*
* json_node_dup_array
* @node: a #JsonNode
*
@@ -337,7 +337,7 @@ json_node_dup_array (JsonNode *node)
return NULL;
}
-/**
+/*
* json_node_get_value:
* @node: a #JsonNode
* @value: return location for an uninitialized value
@@ -366,7 +366,7 @@ node_value_unset (JsonNode *node)
g_value_unset (&(node->data.value));
}
-/**
+/*
* json_node_set_value:
* @node: a #JsonNode
* @value: the #GValue to set
@@ -417,7 +417,7 @@ json_node_set_value (JsonNode *node,
}
-/**
+/*
* json_node_free:
* @node: a #JsonNode
*
@@ -452,7 +452,7 @@ json_node_free (JsonNode *node)
}
}
-/**
+/*
* json_node_type_name:
* @node: a #JsonNode
*
@@ -484,7 +484,7 @@ json_node_type_name (JsonNode *node)
return "unknown";
}
-/**
+/*
* json_node_get_parent:
* @node: a #JsonNode
*
@@ -500,7 +500,7 @@ json_node_get_parent (JsonNode *node)
return node->parent;
}
-/**
+/*
* json_node_set_string:
* @node: a #JsonNode of type %JSON_NODE_VALUE
* @value: a string value
@@ -530,7 +530,7 @@ json_node_set_string (JsonNode *node,
}
}
-/**
+/*
* json_node_get_string:
* @node: a #JsonNode of type %JSON_NODE_VALUE
*
@@ -552,7 +552,7 @@ json_node_get_string (JsonNode *node)
return NULL;
}
-/**
+/*
* json_node_dup_string:
* @node: a #JsonNode of type %JSON_NODE_VALUE
*
@@ -575,7 +575,7 @@ json_node_dup_string (JsonNode *node)
return NULL;
}
-/**
+/*
* json_node_set_int:
* @node: a #JsonNode of type %JSON_NODE_VALUE
* @value: an integer value
@@ -605,7 +605,7 @@ json_node_set_int (JsonNode *node,
}
}
-/**
+/*
* json_node_get_int:
* @node: a #JsonNode of type %JSON_NODE_VALUE
*
@@ -627,7 +627,7 @@ json_node_get_int (JsonNode *node)
return 0;
}
-/**
+/*
* json_node_set_double:
* @node: a #JsonNode of type %JSON_NODE_VALUE
* @value: a double value
@@ -657,7 +657,7 @@ json_node_set_double (JsonNode *node,
}
}
-/**
+/*
* json_node_get_double:
* @node: a #JsonNode of type %JSON_NODE_VALUE
*
@@ -679,7 +679,7 @@ json_node_get_double (JsonNode *node)
return 0.0;
}
-/**
+/*
* json_node_set_boolean:
* @node: a #JsonNode of type %JSON_NODE_VALUE
* @value: a boolean value
@@ -709,7 +709,7 @@ json_node_set_boolean (JsonNode *node,
}
}
-/**
+/*
* json_node_get_boolean:
* @node: a #JsonNode of type %JSON_NODE_VALUE
*
@@ -731,7 +731,7 @@ json_node_get_boolean (JsonNode *node)
return FALSE;
}
-/**
+/*
* json_node_get_node_type:
* @node: a #JsonNode
*
@@ -749,7 +749,7 @@ json_node_get_node_type (JsonNode *node)
return node->type;
}
-/**
+/*
* json_node_is_null:
* @node: a #JsonNode
*
diff --git a/clutter/json/json-object.c b/clutter/json/json-object.c
index d1bbe98cd..f3324976b 100644
--- a/clutter/json/json-object.c
+++ b/clutter/json/json-object.c
@@ -29,7 +29,7 @@
#include "json-types-private.h"
-/**
+/*
* SECTION:json-object
* @short_description: a JSON object representation
*
@@ -64,7 +64,7 @@ json_object_get_type (void)
return object_type;
}
-/**
+/*
* json_object_new:
*
* Creates a new #JsonObject, an JSON object type representation.
@@ -86,7 +86,7 @@ json_object_new (void)
return object;
}
-/**
+/*
* json_object_ref:
* @object: a #JsonObject
*
@@ -106,7 +106,7 @@ json_object_ref (JsonObject *object)
return object;
}
-/**
+/*
* json_object_unref:
* @object: a #JsonObject
*
@@ -144,7 +144,7 @@ object_set_member_internal (JsonObject *object,
node);
}
-/**
+/*
* json_object_add_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -178,7 +178,7 @@ json_object_add_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -204,7 +204,7 @@ json_object_set_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_int_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -232,7 +232,7 @@ json_object_set_int_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_double_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -260,7 +260,7 @@ json_object_set_double_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_boolean_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -288,7 +288,7 @@ json_object_set_boolean_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_string_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -316,7 +316,7 @@ json_object_set_string_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_null_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -341,7 +341,7 @@ json_object_set_null_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_array_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -371,7 +371,7 @@ json_object_set_array_member (JsonObject *object,
object_set_member_internal (object, member_name, node);
}
-/**
+/*
* json_object_set_object_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -448,7 +448,7 @@ g_hash_table_get_values (GHashTable *hash_table)
}
#endif /* GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14 */
-/**
+/*
* json_object_get_members:
* @object: a #JsonObject
*
@@ -468,7 +468,7 @@ json_object_get_members (JsonObject *object)
return g_hash_table_get_keys (object->members);
}
-/**
+/*
* json_object_get_values:
* @object: a #JsonObject
*
@@ -487,7 +487,7 @@ json_object_get_values (JsonObject *object)
return g_hash_table_get_values (object->members);
}
-/**
+/*
* json_object_dup_member:
* @object: a #JsonObject
* @member_name: the name of the JSON object member to access
@@ -523,7 +523,7 @@ object_get_member_internal (JsonObject *object,
return g_hash_table_lookup (object->members, member_name);
}
-/**
+/*
* json_object_get_member:
* @object: a #JsonObject
* @member_name: the name of the JSON object member to access
@@ -544,7 +544,7 @@ json_object_get_member (JsonObject *object,
return object_get_member_internal (object, member_name);
}
-/**
+/*
* json_object_get_int_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -574,7 +574,7 @@ json_object_get_int_member (JsonObject *object,
return json_node_get_int (node);
}
-/**
+/*
* json_object_get_double_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -604,7 +604,7 @@ json_object_get_double_member (JsonObject *object,
return json_node_get_double (node);
}
-/**
+/*
* json_object_get_boolean_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -634,7 +634,7 @@ json_object_get_boolean_member (JsonObject *object,
return json_node_get_boolean (node);
}
-/**
+/*
* json_object_get_null_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -663,7 +663,7 @@ json_object_get_null_member (JsonObject *object,
return JSON_NODE_TYPE (node) == JSON_NODE_NULL;
}
-/**
+/*
* json_object_get_string_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -693,7 +693,7 @@ json_object_get_string_member (JsonObject *object,
return json_node_get_string (node);
}
-/**
+/*
* json_object_get_array_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -723,7 +723,7 @@ json_object_get_array_member (JsonObject *object,
return json_node_get_array (node);
}
-/**
+/*
* json_object_get_object_member:
* @object: a #JsonObject
* @member_name: the name of the member
@@ -753,7 +753,7 @@ json_object_get_object_member (JsonObject *object,
return json_node_get_object (node);
}
-/**
+/*
* json_object_has_member:
* @object: a #JsonObject
* @member_name: the name of a JSON object member
@@ -772,7 +772,7 @@ json_object_has_member (JsonObject *object,
return (g_hash_table_lookup (object->members, member_name) != NULL);
}
-/**
+/*
* json_object_get_size:
* @object: a #JsonObject
*
@@ -788,7 +788,7 @@ json_object_get_size (JsonObject *object)
return g_hash_table_size (object->members);
}
-/**
+/*
* json_object_remove_member:
* @object: a #JsonObject
* @member_name: the name of the member to remove
@@ -827,7 +827,7 @@ json_object_foreach_internal (gpointer key,
clos->func (clos->object, member_name, member_node, clos->data);
}
-/**
+/*
* json_object_foreach_member:
* @object: a #JsonObject
* @func: the function to be called on each member
diff --git a/clutter/json/json-parser.c b/clutter/json/json-parser.c
index 3ef5afb93..0cd2f64e4 100644
--- a/clutter/json/json-parser.c
+++ b/clutter/json/json-parser.c
@@ -17,7 +17,7 @@
* Emmanuele Bassi
*/
-/**
+/*
* SECTION:json-parser
* @short_description: Parse JSON data streams
*
@@ -167,7 +167,7 @@ json_parser_class_init (JsonParserClass *klass)
gobject_class->dispose = json_parser_dispose;
- /**
+ /*
* JsonParser::parse-start:
* @parser: the #JsonParser that received the signal
*
@@ -182,7 +182,7 @@ json_parser_class_init (JsonParserClass *klass)
NULL, NULL,
_json_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- /**
+ /*
* JsonParser::parse-end:
* @parser: the #JsonParser that received the signal
*
@@ -197,7 +197,7 @@ json_parser_class_init (JsonParserClass *klass)
NULL, NULL,
_json_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- /**
+ /*
* JsonParser::object-start:
* @parser: the #JsonParser that received the signal
*
@@ -212,7 +212,7 @@ json_parser_class_init (JsonParserClass *klass)
NULL, NULL,
_json_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- /**
+ /*
* JsonParser::object-member:
* @parser: the #JsonParser that received the signal
* @object: a #JsonObject
@@ -232,7 +232,7 @@ json_parser_class_init (JsonParserClass *klass)
G_TYPE_NONE, 2,
JSON_TYPE_OBJECT,
G_TYPE_STRING);
- /**
+ /*
* JsonParser::object-end:
* @parser: the #JsonParser that received the signal
* @object: the parsed #JsonObject
@@ -249,7 +249,7 @@ json_parser_class_init (JsonParserClass *klass)
_json_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
JSON_TYPE_OBJECT);
- /**
+ /*
* JsonParser::array-start:
* @parser: the #JsonParser that received the signal
*
@@ -264,7 +264,7 @@ json_parser_class_init (JsonParserClass *klass)
NULL, NULL,
_json_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- /**
+ /*
* JsonParser::array-element:
* @parser: the #JsonParser that received the signal
* @array: a #JsonArray
@@ -284,7 +284,7 @@ json_parser_class_init (JsonParserClass *klass)
G_TYPE_NONE, 2,
JSON_TYPE_ARRAY,
G_TYPE_INT);
- /**
+ /*
* JsonParser::array-end:
* @parser: the #JsonParser that received the signal
* @array: the parsed #JsonArrary
@@ -301,7 +301,7 @@ json_parser_class_init (JsonParserClass *klass)
_json_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
JSON_TYPE_ARRAY);
- /**
+ /*
* JsonParser::error:
* @parser: the parser instance that received the signal
* @error: a pointer to the #GError
@@ -885,7 +885,7 @@ json_scanner_new (JsonParser *parser)
return scanner;
}
-/**
+/*
* json_parser_new:
*
* Creates a new #JsonParser instance. You can use the #JsonParser to
@@ -901,7 +901,7 @@ json_parser_new (void)
return g_object_new (JSON_TYPE_PARSER, NULL);
}
-/**
+/*
* json_parser_load_from_file:
* @parser: a #JsonParser
* @filename: the path for the file to parse
@@ -944,7 +944,7 @@ json_parser_load_from_file (JsonParser *parser,
return retval;
}
-/**
+/*
* json_parser_load_from_data:
* @parser: a #JsonParser
* @data: the buffer to parse
@@ -1067,7 +1067,7 @@ json_parser_load_from_data (JsonParser *parser,
return retval;
}
-/**
+/*
* json_parser_get_root:
* @parser: a #JsonParser
*
@@ -1084,7 +1084,7 @@ json_parser_get_root (JsonParser *parser)
return parser->priv->root;
}
-/**
+/*
* json_parser_get_current_line:
* @parser: a #JsonParser
*
@@ -1103,7 +1103,7 @@ json_parser_get_current_line (JsonParser *parser)
return 0;
}
-/**
+/*
* json_parser_get_current_pos:
* @parser: a #JsonParser
*
diff --git a/configure.ac b/configure.ac
index 6b4507315..5b107d8e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -799,8 +799,8 @@ PKG_CHECK_MODULES(CLUTTER_DEPS, [$CLUTTER_REQUIRES])
AC_SUBST(CLUTTER_REQUIRES)
-CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_PROFILE_CFLAGS $GLIB_CFLAGS"
-CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $X11_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_PROFILE_LDFLAGS $GLIB_LIBS"
+CLUTTER_CFLAGS="$EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS $CLUTTER_PROFILE_CFLAGS $GLIB_CFLAGS"
+CLUTTER_LIBS="$EGL_LIBS $X11_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS $CLUTTER_PROFILE_LDFLAGS $GLIB_LIBS"
AC_SUBST(CLUTTER_CFLAGS)
AC_SUBST(CLUTTER_LIBS)
@@ -811,7 +811,7 @@ GOBJECT_INTROSPECTION_CHECK([0.6.7])
dnl === GTK Doc check =========================================================
-GTK_DOC_CHECK([1.13])
+GTK_DOC_CHECK([1.13], [--flavour no-tmpl])
# we don't want to build the documentation from a Git clone unless we
# explicitly tell configure to do so; this allows avoiding to recurse into
diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am
index bcedb36ec..f0486c28c 100644
--- a/doc/reference/clutter/Makefile.am
+++ b/doc/reference/clutter/Makefile.am
@@ -38,6 +38,7 @@ MKTMPL_OPTIONS=
# Extra options to supply to gtkdoc-fixref. Not normally needed.
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
FIXXREF_OPTIONS=\
+ --extra-dir=../cogl/html \
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \
--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \
--extra-dir=$(CAIRO_PREFIX)/share/gtk-doc/html/cairo \
@@ -64,6 +65,7 @@ CFILE_GLOB=$(top_srcdir)/clutter/*.c \
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=\
clutter.h \
+ clutter-actor-meta-private.h \
clutter-bezier.h \
clutter-debug.h \
clutter-deprecated.h \
@@ -83,7 +85,7 @@ IGNORE_HFILES=\
cogl \
eglnative \
eglx \
- fruity \
+ fruity \
glx \
osx \
x11 \
diff --git a/doc/reference/clutter/clutter-docs.xml.in b/doc/reference/clutter/clutter-docs.xml.in
index 2fa61f3ca..080d3297b 100644
--- a/doc/reference/clutter/clutter-docs.xml.in
+++ b/doc/reference/clutter/clutter-docs.xml.in
@@ -60,6 +60,7 @@
+
@@ -88,6 +89,16 @@
+
+ Actor Modifiers
+
+
+
+
+
+
+
+
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 7c65d53d4..ae870b997 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -274,7 +274,6 @@ CLUTTER_ACTOR_IS_REACTIVE
ClutterActorFlags
ClutterRequestMode
-ClutterGeometry
CLUTTER_CALLBACK
ClutterCallback
ClutterActor
@@ -409,6 +408,22 @@ clutter_actor_set_text_direction
clutter_actor_get_text_direction
clutter_actor_has_pointer
+
+clutter_actor_add_action
+clutter_actor_add_action_with_name
+clutter_actor_remove_action
+clutter_actor_remove_action_by_name
+clutter_actor_get_actions
+clutter_actor_get_action
+clutter_actor_clear_actions
+clutter_actor_add_constraint
+clutter_actor_add_constraint_with_name
+clutter_actor_remove_constraint
+clutter_actor_remove_constraint_by_name
+clutter_actor_get_constraints
+clutter_actor_get_constraint
+clutter_actor_clear_constraints
+
ClutterActorBox
clutter_actor_box_new
@@ -434,6 +449,10 @@ clutter_vertex_copy
clutter_vertex_free
clutter_vertex_equal
+
+ClutterGeometry
+clutter_geometry_union
+
CLUTTER_TYPE_GEOMETRY
CLUTTER_TYPE_ACTOR_BOX
@@ -444,7 +463,9 @@ CLUTTER_TYPE_ACTOR
CLUTTER_ACTOR_CLASS
CLUTTER_IS_ACTOR_CLASS
CLUTTER_ACTOR_GET_CLASS
+
+ClutterRedrawFlags
ClutterActorPrivate
clutter_actor_get_type
clutter_actor_box_get_type
@@ -1712,6 +1733,9 @@ clutter_text_get_type
ClutterAnimatable
ClutterAnimatableIface
clutter_animatable_animate_property
+clutter_animatable_find_property
+clutter_animatable_get_initial_state
+clutter_animatable_set_final_state
CLUTTER_TYPE_ANIMATABLE
@@ -1993,6 +2017,8 @@ clutter_box_layout_set_spacing
clutter_box_layout_get_spacing
clutter_box_layout_set_vertical
clutter_box_layout_get_vertical
+clutter_box_layout_set_homogeneous
+clutter_box_layout_get_homogeneous
clutter_box_layout_pack
@@ -2075,3 +2101,120 @@ clutter_animator_get_type
clutter_animator_key_get_type
ClutterAnimatorPrivate
+
+
+clutter-actor-meta
+ClutterActorMeta
+ClutterActorMeta
+ClutterActorMetaClass
+clutter_actor_meta_set_name
+clutter_actor_meta_get_name
+clutter_actor_meta_set_enabled
+clutter_actor_meta_get_enabled
+
+
+clutter_actor_meta_get_actor
+
+
+CLUTTER_TYPE_ACTOR_META
+CLUTTER_ACTOR_META
+CLUTTER_ACTOR_META_CLASS
+CLUTTER_IS_ACTOR_META
+CLUTTER_IS_ACTOR_META_CLASS
+CLUTTER_ACTOR_META_GET_CLASS
+clutter_actor_meta_get_type
+
+
+ClutterActorMetaPrivate
+
+
+
+clutter-action
+ClutterAction
+ClutterAction
+ClutterActionClass
+
+
+CLUTTER_TYPE_ACTION
+CLUTTER_ACTION
+CLUTTER_ACTION_CLASS
+CLUTTER_IS_ACTION
+CLUTTER_IS_ACTION_CLASS
+CLUTTER_ACTION_GET_CLASS
+clutter_action_get_type
+
+
+
+clutter-constraint
+ClutterConstraint
+ClutterConstraint
+ClutterConstraintClass
+
+
+CLUTTER_TYPE_CONSTRAINT
+CLUTTER_CONSTRAINT
+CLUTTER_CONSTRAINT_CLASS
+CLUTTER_IS_CONSTRAINT
+CLUTTER_IS_CONSTRAINT_CLASS
+CLUTTER_CONSTRAINT_GET_CLASS
+clutter_constraint_get_type
+
+
+
+clutter-drag-action
+ClutterDragAction
+ClutterDragAction
+ClutterDragActionClass
+clutter_drag_action_new
+clutter_drag_action_set_drag_threshold
+clutter_drag_action_get_drag_threshold
+clutter_drag_action_set_drag_handle
+clutter_drag_action_get_drag_handle
+ClutterDragAxis
+clutter_drag_action_set_drag_axis
+clutter_drag_action_get_drag_axis
+
+
+clutter_drag_action_get_press_coords
+clutter_drag_action_get_motion_coords
+
+
+CLUTTER_TYPE_DRAG_ACTION
+CLUTTER_DRAG_ACTION
+CLUTTER_DRAG_ACTION_CLASS
+CLUTTER_IS_DRAG_ACTION
+CLUTTER_IS_DRAG_ACTION_CLASS
+CLUTTER_DRAG_ACTION_GET_CLASS
+clutter_drag_action_get_type
+
+
+ClutterDragActionPrivate
+
+
+
+clutter-bind-constraint
+ClutterBindConstraint
+ClutterBindConstraint
+ClutterBindCoordinate
+clutter_bind_constraint_new
+
+
+CLUTTER_TYPE_BIND_CONSTRAINT
+CLUTTER_BIND_CONSTRAINT
+CLUTTER_IS_BIND_CONSTRAINT
+clutter_bind_constraint_get_type
+
+
+
+clutter-align-constraint
+ClutterAlignConstraint
+ClutterAlignConstraint
+ClutterAlignAxis
+clutter_align_constraint_new
+
+
+CLUTTER_TYPE_ALIGN_CONSTRAINT
+CLUTTER_ALIGN_CONSTRAINT
+CLUTTER_IS_ALIGN_CONSTRAINT
+clutter_align_constraint_get_type
+
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types
index 21b6a809d..ce8d6ab13 100644
--- a/doc/reference/clutter/clutter.types
+++ b/doc/reference/clutter/clutter.types
@@ -43,3 +43,9 @@ clutter_box_layout_get_type
clutter_input_device_get_type
clutter_device_manager_get_type
clutter_animator_get_type
+clutter_actor_meta_get_type
+clutter_action_get_type
+clutter_drag_action_get_type
+clutter_constraint_get_type
+clutter_bind_constraint_get_type
+clutter_align_constraint_get_type
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index b7e6295d3..19f829177 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -48,7 +48,9 @@ UNIT_TESTS = \
test-bin-layout.c \
test-flow-layout.c \
test-box-layout.c \
- test-stage-sizing.c
+ test-stage-sizing.c \
+ test-drag.c \
+ test-constraints.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c
diff --git a/tests/interactive/test-constraints.c b/tests/interactive/test-constraints.c
new file mode 100644
index 000000000..9efb55dab
--- /dev/null
+++ b/tests/interactive/test-constraints.c
@@ -0,0 +1,173 @@
+#include
+#include
+#include
+
+#define H_PADDING 32
+#define V_PADDING 32
+
+enum
+{
+ NorthWest, North, NorthEast,
+ West, Center, East,
+ SouthWest, South, SouthEast,
+
+ N_RECTS
+};
+
+static ClutterActor *rects[N_RECTS] = { NULL, };
+static const gchar *colors[N_RECTS] = {
+ "#8ae234", "#73d216", "#4e9a06",
+ "#729fcf", "#3465a4", "#204a87",
+ "#ef2929", "#cc0000", "#a40000"
+};
+
+static gboolean is_expanded = FALSE;
+
+static gboolean
+on_button_release (ClutterActor *actor,
+ ClutterEvent *event,
+ gpointer data G_GNUC_UNUSED)
+{
+ if (!is_expanded)
+ {
+ gfloat north_offset, south_offset;
+ gfloat west_offset, east_offset;
+
+ north_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING)
+ * -1.0f;
+ south_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING);
+
+ west_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING)
+ * -1.0f;
+ east_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING);
+
+ clutter_actor_animate (rects[NorthWest], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", west_offset,
+ "@constraints.y-bind.offset", north_offset,
+ NULL);
+ clutter_actor_animate (rects[North], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.y-bind.offset", north_offset,
+ NULL);
+ clutter_actor_animate (rects[NorthEast], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", east_offset,
+ "@constraints.y-bind.offset", north_offset,
+ NULL);
+
+ clutter_actor_animate (rects[West], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", west_offset,
+ NULL);
+ clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
+ "opacity", 128,
+ NULL);
+ clutter_actor_animate (rects[East], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", east_offset,
+ NULL);
+
+ clutter_actor_animate (rects[SouthWest], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", west_offset,
+ "@constraints.y-bind.offset", south_offset,
+ NULL);
+ clutter_actor_animate (rects[South], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.y-bind.offset", south_offset,
+ NULL);
+ clutter_actor_animate (rects[SouthEast], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 255,
+ "@constraints.x-bind.offset", east_offset,
+ "@constraints.y-bind.offset", south_offset,
+ NULL);
+ }
+ else
+ {
+ gint i;
+
+ clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
+ "opacity", 255,
+ NULL);
+
+ for (i = NorthWest; i < N_RECTS; i++)
+ {
+ if (i == Center)
+ continue;
+
+ clutter_actor_animate (rects[i], CLUTTER_EASE_OUT_CUBIC, 500,
+ "opacity", 0,
+ "@constraints.x-bind.offset", 0.0f,
+ "@constraints.y-bind.offset", 0.0f,
+ NULL);
+ }
+ }
+
+ is_expanded = !is_expanded;
+
+ return TRUE;
+}
+
+G_MODULE_EXPORT int
+test_constraints_main (int argc, char *argv[])
+{
+ ClutterActor *stage, *rect;
+ ClutterConstraint *constraint;
+ ClutterColor rect_color;
+ gint i;
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_new ();
+ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+ clutter_stage_set_title (CLUTTER_STAGE (stage), "Constraints");
+ clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+ clutter_actor_set_size (stage, 800, 600);
+
+ /* main rect */
+ clutter_color_from_string (&rect_color, "#3465a4");
+ rect = clutter_rectangle_new ();
+ g_signal_connect (rect, "button-release-event",
+ G_CALLBACK (on_button_release),
+ NULL);
+ clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
+ clutter_actor_set_size (rect, 128, 128);
+ clutter_actor_set_reactive (rect, TRUE);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
+
+ constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.5);
+ clutter_actor_add_constraint_with_name (rect, "x-align", constraint);
+
+ constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.5);
+ clutter_actor_add_constraint_with_name (rect, "y-align", constraint);
+
+ rects[Center] = rect;
+
+ for (i = 0; i < N_RECTS; i++)
+ {
+ if (i == Center)
+ continue;
+
+ clutter_color_from_string (&rect_color, colors[i]);
+ rect = clutter_rectangle_new ();
+ clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
+ clutter_actor_set_size (rect, 128, 128);
+ clutter_actor_set_opacity (rect, 0);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
+
+ constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_X, 0.0);
+ clutter_actor_add_constraint_with_name (rect, "x-bind", constraint);
+
+ constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0);
+ clutter_actor_add_constraint_with_name (rect, "y-bind", constraint);
+
+ rects[i] = rect;
+ }
+
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/interactive/test-drag.c b/tests/interactive/test-drag.c
new file mode 100644
index 000000000..e8c479cfd
--- /dev/null
+++ b/tests/interactive/test-drag.c
@@ -0,0 +1,189 @@
+#include
+#include
+#include
+
+static void
+on_drag_begin (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ gint button,
+ ClutterModifierType modifiers)
+{
+ gboolean is_copy = (modifiers & CLUTTER_SHIFT_MASK) ? TRUE : FALSE;
+ ClutterActor *drag_handle = NULL;
+
+ if (is_copy)
+ {
+ ClutterActor *stage = clutter_actor_get_stage (actor);
+ ClutterColor handle_color;
+
+ drag_handle = clutter_rectangle_new ();
+ clutter_actor_set_size (drag_handle, 48, 48);
+
+ clutter_color_from_string (&handle_color, "#204a87aa");
+ clutter_rectangle_set_color (CLUTTER_RECTANGLE (drag_handle), &handle_color);
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), drag_handle);
+ clutter_actor_set_position (drag_handle, event_x, event_y);
+ }
+ else
+ drag_handle = actor;
+
+ clutter_drag_action_set_drag_handle (action, drag_handle);
+
+ clutter_actor_set_opacity (actor, 128);
+}
+
+static void
+on_drag_motion (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat delta_x,
+ gfloat delta_y,
+ ClutterModifierType modifiers)
+{
+ ClutterActor *drag_handle;
+
+ drag_handle = clutter_drag_action_get_drag_handle (action);
+ g_assert (drag_handle != NULL);
+
+ clutter_actor_move_by (drag_handle, delta_x, delta_y);
+}
+
+static void
+on_drag_end (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ gint button,
+ ClutterModifierType modifiers)
+{
+ ClutterActor *drag_handle;
+
+ drag_handle = clutter_drag_action_get_drag_handle (action);
+ if (actor != drag_handle)
+ {
+ gfloat real_x, real_y;
+ ClutterActor *parent;
+
+ /* if we are dragging a copy we can destroy the copy now
+ * and animate the real actor to the drop coordinates,
+ * transformed in the parent's coordinate space
+ */
+ clutter_actor_animate (drag_handle, CLUTTER_LINEAR, 150,
+ "opacity", 0,
+ "signal-swapped-after::completed",
+ G_CALLBACK (clutter_actor_destroy),
+ drag_handle,
+ NULL);
+
+ parent = clutter_actor_get_parent (actor);
+ clutter_actor_transform_stage_point (parent, event_x, event_y,
+ &real_x,
+ &real_y);
+
+ clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 150,
+ "opacity", 255,
+ "x", real_x,
+ "y", real_y,
+ NULL);
+ }
+ else
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 150,
+ "opacity", 255,
+ NULL);
+}
+
+static ClutterDragAxis
+get_drag_axis (const gchar *str)
+{
+ if (str == NULL || *str == '\0')
+ return CLUTTER_DRAG_AXIS_NONE;
+
+ if (*str == 'x' || *str == 'X')
+ return CLUTTER_DRAG_X_AXIS;
+
+ if (*str == 'y' || *str == 'Y')
+ return CLUTTER_DRAG_Y_AXIS;
+
+ g_warn_if_reached ();
+
+ return CLUTTER_DRAG_AXIS_NONE;
+}
+
+static gchar *drag_axis = NULL;
+static gint drag_threshold = 0;
+
+static GOptionEntry entries[] = {
+ {
+ "threshold", 't',
+ 0,
+ G_OPTION_ARG_INT,
+ &drag_threshold,
+ "Set the drag threshold", "PIXELS"
+ },
+ {
+ "axis", 'a',
+ 0,
+ G_OPTION_ARG_STRING,
+ &drag_axis,
+ "Set the drag axis", "AXIS"
+ },
+
+ { NULL }
+};
+
+G_MODULE_EXPORT int
+test_drag_main (int argc, char *argv[])
+{
+ ClutterActor *stage, *handle;
+ ClutterAction *action;
+ ClutterColor handle_color;
+ GError *error;
+
+ error = NULL;
+ clutter_init_with_args (&argc, &argv,
+ "test-drag",
+ entries,
+ NULL,
+ &error);
+ if (error != NULL)
+ {
+ g_print ("Unable to run test-drag: %s\n", error->message);
+ g_error_free (error);
+
+ return EXIT_FAILURE;
+ }
+
+ stage = clutter_stage_new ();
+ clutter_stage_set_title (CLUTTER_STAGE (stage), "Drag Test");
+ clutter_actor_set_size (stage, 800, 600);
+ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+ clutter_color_from_string (&handle_color, "#729fcfff");
+
+ handle = clutter_rectangle_new ();
+ clutter_rectangle_set_color (CLUTTER_RECTANGLE (handle), &handle_color);
+ clutter_actor_set_size (handle, 128, 128);
+ clutter_actor_set_position (handle, (800 - 128) / 2, (600 - 128) / 2);
+ clutter_actor_set_reactive (handle, TRUE);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), handle);
+
+ action = clutter_drag_action_new ();
+ clutter_drag_action_set_drag_threshold (CLUTTER_DRAG_ACTION (action),
+ drag_threshold);
+ clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action),
+ get_drag_axis (drag_axis));
+
+ g_signal_connect (action, "drag-begin", G_CALLBACK (on_drag_begin), NULL);
+ g_signal_connect (action, "drag-motion", G_CALLBACK (on_drag_motion), NULL);
+ g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);
+
+ clutter_actor_add_action (handle, action);
+
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}