+2007-05-14 Matthew Allum <mallum@openedhand.com>
+
+ * clutter/clutter-behaviour-path.c:
+ Fix bug where last knot position wouldn't get reached.
+
+ * clutter/clutter-group.c:
+ Add some docs
+
+ * clutter/clutter-timeline.h:
+ * clutter/clutter-timeline.c:
+ Add clutter_timeline_copy (needed for ClutterEffect)
+
+ * clutter/clutter-version.h.in:
+ Export windowing system / GL backend etc defines.
+
+ * clutter/Makefile.am:
+ * clutter/clutter-effect.c:
+ * clutter/clutter-effect.h:
+ * clutter/clutter.h:
+
+ * clutter/glx/clutter-backend-glx.c:
+ Minor clean ups.
+
+ * clutter/clutter-alpha.h:
+ Add a fixme.
+
+ * configure.ac:
+ Add FPU define.
+
+ * examples/Makefile.am:
+ * examples/slider.c:
+ Add Robs slider game.
+
2007-05-10 Matthew Allum <mallum@openedhand.com>
* clutter/egl/clutter-backend-egl.c:
$(srcdir)/clutter-stage.h \
$(srcdir)/clutter-texture.h \
$(srcdir)/clutter-timeline.h \
+ $(srcdir)/clutter-effect.h \
$(srcdir)/clutter-util.h \
$(srcdir)/clutter-version.h \
$(NULL)
clutter-rectangle.c \
clutter-texture.c \
clutter-timeline.c \
+ $(srcdir)/clutter-effect.c \
clutter-util.c \
$(NULL)
#define CLUTTER_ALPHA_RAMP_DEC clutter_ramp_dec_func
#define CLUTTER_ALPHA_RAMP clutter_ramp_func
#define CLUTTER_ALPHA_SINE clutter_sine_func
+/* FIXME add SINE_INC/DEC */
#define CLUTTER_ALPHA_SQUARE clutter_square_func
guint32 clutter_ramp_inc_func (ClutterAlpha *alpha,
{
ClutterKnot *knot = data;
+ CLUTTER_NOTE (BEHAVIOUR, "Setting actor to %ix%i", knot->x, knot->y);
+
clutter_actor_set_position (actor, knot->x, knot->y);
}
total_len = path_total_length (behave);
offset = (alpha * total_len) / CLUTTER_ALPHA_MAX_ALPHA;
+ CLUTTER_NOTE (BEHAVIOUR, "alpha %i vs %i, len: %i vs %i",
+ alpha, CLUTTER_ALPHA_MAX_ALPHA,
+ offset, total_len);
+
if (offset == 0)
{
+ /* first knot */
clutter_behaviour_actors_foreach (behaviour,
actor_apply_knot_foreach,
priv->knots->data);
priv->knots->data);
return;
}
+
+ if (offset == total_len)
+ {
+ /* Special case for last knot */
+ ClutterKnot *last_knot = (g_slist_last (priv->knots))->data;
+
+ clutter_behaviour_actors_foreach (behaviour,
+ actor_apply_knot_foreach,
+ last_knot);
+
+ g_signal_emit (behave, path_signals[KNOT_REACHED], 0, last_knot);
+
+ return;
+ }
for (l = priv->knots; l != NULL; l = l->next)
{
ClutterKnot *next = l->next->data;
dist_to_next = node_distance (knot, next);
+
if (offset >= dist && offset < (dist + dist_to_next))
{
ClutterKnot new;
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum <mallum@openedhand.com>
+ * Jorn Baayen <jorn@openedhand.com>
+ * Emmanuele Bassi <ebassi@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:clutter-effect-template
+ * @short_description: A utility class
+ *
+ *
+ * Since: 0.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include "clutter-alpha.h"
+#include "clutter-main.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+#include "clutter-debug.h"
+#include "clutter-behaviour-bspline.h"
+#include "clutter-behaviour-ellipse.h"
+#include "clutter-behaviour-opacity.h"
+#include "clutter-behaviour-path.h"
+#include "clutter-behaviour-rotate.h"
+#include "clutter-behaviour-scale.h"
+
+#include "clutter-effect.h"
+
+typedef struct ClutterEffectClosure
+{
+ ClutterActor *actor;
+ ClutterTimeline *timeline;
+ ClutterAlpha *alpha;
+ ClutterBehaviour *behave;
+ gulong signal_id;
+ ClutterEffectCompleteFunc completed_func;
+ gpointer completed_data;
+ ClutterEffectTemplate *template;
+}
+ClutterEffectClosure;
+
+G_DEFINE_TYPE (ClutterEffectTemplate, clutter_effect_template, G_TYPE_OBJECT);
+
+#define EFFECT_TEMPLATE_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE, \
+ ClutterEffectTemplatePrivate))
+
+typedef struct _ClutterEffectTemplatePrivate ClutterEffectTemplatePrivate;
+
+struct _ClutterEffectTemplatePrivate
+{
+ ClutterTimeline *timeline;
+ ClutterAlphaFunc alpha_func;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ALPHA_FUNC,
+ PROP_TIMELINE,
+};
+
+static void
+clutter_effect_template_dispose (GObject *object)
+{
+ ClutterEffectTemplate *template;
+ ClutterEffectTemplatePrivate *priv;
+
+ template = CLUTTER_EFFECT_TEMPLATE(object);
+ priv = EFFECT_TEMPLATE_PRIVATE(template);
+
+ g_object_unref (priv->timeline);
+
+ priv->timeline = NULL;
+ priv->alpha_func = NULL;
+
+ if (G_OBJECT_CLASS (clutter_effect_template_parent_class)->dispose)
+ G_OBJECT_CLASS (clutter_effect_template_parent_class)->dispose (object);
+}
+
+static void
+clutter_effect_template_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (clutter_effect_template_parent_class)->finalize (object);
+}
+
+static void
+clutter_effect_template_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterEffectTemplate *template;
+ ClutterEffectTemplatePrivate *priv;
+
+ template = CLUTTER_EFFECT_TEMPLATE(object);
+ priv = EFFECT_TEMPLATE_PRIVATE(template);
+
+ switch (prop_id)
+ {
+ case PROP_ALPHA_FUNC:
+ priv->alpha_func = g_value_get_pointer (value);
+ break;
+ case PROP_TIMELINE:
+ priv->timeline = g_value_get_object (value);
+ g_object_ref(priv->timeline);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_effect_template_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterEffectTemplate *template;
+ ClutterEffectTemplatePrivate *priv;
+
+ template = CLUTTER_EFFECT_TEMPLATE(object);
+ priv = EFFECT_TEMPLATE_PRIVATE(template);
+
+ switch (prop_id)
+ {
+ case PROP_ALPHA_FUNC:
+ g_value_set_pointer (value, priv->alpha_func);
+ break;
+ case PROP_TIMELINE:
+ g_value_set_object (value, priv->timeline);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+clutter_effect_template_class_init (ClutterEffectTemplateClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ClutterEffectTemplatePrivate));
+
+ object_class->dispose = clutter_effect_template_dispose;
+ object_class->finalize = clutter_effect_template_finalize;
+
+ object_class->set_property = clutter_effect_template_set_property;
+ object_class->get_property = clutter_effect_template_get_property;
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ALPHA_FUNC,
+ g_param_spec_pointer ("alpha-func",
+ "Alpha-Function",
+ "Alpha reference Function",
+ G_PARAM_CONSTRUCT_ONLY |
+ CLUTTER_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_TIMELINE,
+ g_param_spec_object ("timeline",
+ "Timeline",
+ "Timeline to use as a reference for the Template",
+ CLUTTER_TYPE_TIMELINE,
+ G_PARAM_CONSTRUCT_ONLY |
+ CLUTTER_PARAM_READWRITE));
+}
+
+static void
+clutter_effect_template_init (ClutterEffectTemplate *self)
+{
+}
+
+/**
+ * clutter_effect_template_new:
+ *
+ * FIXME
+ *
+ * Return value: a #ClutterEffectTemplate
+ *
+ * Since: 0.4
+ */
+ClutterEffectTemplate*
+clutter_effect_template_new (ClutterTimeline *timeline,
+ ClutterAlphaFunc alpha_func)
+{
+ return g_object_new (CLUTTER_TYPE_EFFECT_TEMPLATE,
+ "timeline", timeline,
+ "alpha-func", alpha_func,
+ NULL);
+}
+
+static void
+clutter_effect_closure_destroy (ClutterEffectClosure *c)
+{
+ g_signal_handler_disconnect (c->timeline, c->signal_id);
+ clutter_behaviour_remove (c->behave, c->actor);
+
+ g_object_unref (c->actor);
+ g_object_unref (c->template);
+ g_object_unref (c->behave);
+ g_object_unref (c->alpha);
+ g_object_unref (c->timeline);
+
+ g_slice_free (ClutterEffectClosure, c);
+}
+
+static ClutterEffectClosure*
+clutter_effect_closure_new (ClutterEffectTemplate *template,
+ ClutterActor *actor,
+ GCallback complete)
+{
+ ClutterEffectClosure *c;
+ ClutterEffectTemplatePrivate *priv = EFFECT_TEMPLATE_PRIVATE(template);
+
+ c = g_slice_new0(ClutterEffectClosure);
+
+ g_object_ref (actor);
+ g_object_ref (template);
+
+ c->template = template;
+ c->actor = actor;
+ c->timeline = clutter_timeline_copy (priv->timeline);
+ c->alpha = clutter_alpha_new_full (c->timeline,
+ priv->alpha_func,
+ NULL, NULL);
+
+ c->signal_id = g_signal_connect (c->timeline,
+ "completed",
+ G_CALLBACK(complete),
+ c);
+ return c;
+}
+
+static void
+on_effect_complete (ClutterTimeline *timeline,
+ gpointer user_data)
+{
+ ClutterEffectClosure *c = (ClutterEffectClosure*)user_data;
+
+ if (c->completed_func)
+ c->completed_func(c->actor, c->completed_data);
+
+ clutter_effect_closure_destroy (c);
+}
+
+/**
+ * clutter_effect_fade:
+ *
+ * FIXME
+ *
+ * Return value: an alpha value.
+ *
+ * Since: 0.4
+ */
+ClutterTimeline*
+clutter_effect_fade (ClutterEffectTemplate *template,
+ ClutterActor *actor,
+ guint8 start_opacity,
+ guint8 end_opacity,
+ ClutterEffectCompleteFunc completed_func,
+ gpointer completed_userdata)
+{
+ ClutterEffectClosure *c;
+
+ c = clutter_effect_closure_new (template,
+ actor,
+ G_CALLBACK (on_effect_complete));
+
+ c->completed_func = completed_func;
+ c->completed_data = completed_userdata;
+
+ c->behave = clutter_behaviour_opacity_new (c->alpha,
+ start_opacity,
+ end_opacity);
+
+ clutter_behaviour_apply (c->behave, actor);
+ clutter_timeline_start (c->timeline);
+
+ return c->timeline;
+}
+
+/**
+ * clutter_effect_move:
+ *
+ * FIXME
+ *
+ * Return value: an alpha value.
+ *
+ * Since: 0.4
+ */
+ClutterTimeline*
+clutter_effect_move (ClutterEffectTemplate *template,
+ ClutterActor *actor,
+ const ClutterKnot *knots,
+ guint n_knots,
+ ClutterEffectCompleteFunc completed_func,
+ gpointer completed_userdata)
+{
+ ClutterEffectClosure *c;
+
+ c = clutter_effect_closure_new (template,
+ actor,
+ G_CALLBACK (on_effect_complete));
+
+ c->completed_func = completed_func;
+ c->completed_data = completed_userdata;
+
+ c->behave = clutter_behaviour_path_new (c->alpha, knots, n_knots);
+
+ clutter_behaviour_apply (c->behave, actor);
+ clutter_timeline_start (c->timeline);
+
+ return c->timeline;
+}
--- /dev/null
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006, 2007 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CLUTTER_EFFECT
+#define _CLUTTER_EFFECT
+
+#include <glib-object.h>
+#include <clutter/clutter-timeline.h>
+#include <clutter/clutter-alpha.h>
+#include <clutter/clutter-behaviour.h>
+
+G_BEGIN_DECLS
+
+typedef void (*ClutterEffectCompleteFunc) (ClutterActor *actor,
+ gpointer user_data);
+
+#define CLUTTER_TYPE_EFFECT_TEMPLATE clutter_effect_template_get_type()
+
+#define CLUTTER_EFFECT_TEMPLATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE, ClutterEffectTemplate))
+
+#define CLUTTER_EFFECT_TEMPLATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE, ClutterEffectTemplateClass))
+
+#define CLUTTER_IS_EFFECT_TEMPLATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE))
+
+#define CLUTTER_IS_EFFECT_TEMPLATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE))
+
+#define CLUTTER_EFFECT_TEMPLATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CLUTTER_TYPE_EFFECT_TEMPLATE, ClutterEffectTemplateClass))
+
+typedef struct {
+ GObject parent;
+} ClutterEffectTemplate;
+
+typedef struct {
+ GObjectClass parent_class;
+} ClutterEffectTemplateClass;
+
+GType clutter_effect_template_get_type (void);
+
+ClutterEffectTemplate*
+clutter_effect_template_new (ClutterTimeline *timeline,
+ ClutterAlphaFunc alpha_func);
+
+ClutterTimeline*
+clutter_effect_fade (ClutterEffectTemplate *template,
+ ClutterActor *actor,
+ guint8 start_opacity,
+ guint8 end_opacity,
+ ClutterEffectCompleteFunc completed_func,
+ gpointer completed_data);
+
+ClutterTimeline*
+clutter_effect_move (ClutterEffectTemplate *template,
+ ClutterActor *actor,
+ const ClutterKnot *knots,
+ guint n_knots,
+ ClutterEffectCompleteFunc completed_func,
+ gpointer completed_data);
+
+
+G_END_DECLS
+
+#endif /* _CLUTTER_EFFECT */
+
+G_END_DECLS
+
/**
* SECTION:clutter-group
- * @short_description: Base class for actors which contain multiple child
+ * @short_description: Actor class containing multiple children.
* actors.
*
- * A #ClutterGroup is an Actor which can contain multiple child actors.
+ * A #ClutterGroup is an Actor which contains multiple child actors positioned
+ * relative to the #ClutterGroup position. Other operations such as scaling,
+ * rotating and clipping of the group will child actors.
+ *
+ * A ClutterGroup's size is defined by the size and position of it
+ * it children. Resize requests via parent #ClutterActor will be ignored.
*/
#include "config.h"
}
/**
+ * clutter_timeline_copy:
+ * @timeline: #ClutterTimeline to duplicate.
+ *
+ * Create a new #ClutterTimeline instance which has property values
+ * matching that of supplied timeline.
+ *
+ * Return Value: a new #ClutterTimeline
+ *
+ * Since 0.4
+ */
+ClutterTimeline*
+clutter_timeline_copy (ClutterTimeline *timeline)
+{
+ ClutterTimeline *copy;
+
+ g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
+
+ copy = g_object_new (CLUTTER_TYPE_TIMELINE, NULL);
+
+ copy->priv->fps = timeline->priv->fps;
+ copy->priv->n_frames = timeline->priv->n_frames;
+ copy->priv->loop = timeline->priv->loop;
+
+ return copy;
+}
+
+/**
* clutter_timeline_new:
* @n_frames: the number of frames
* @fps: the number of frames per second
guint n_frames);
guint clutter_timeline_get_n_frames (ClutterTimeline *timeline);
gboolean clutter_timeline_is_playing (ClutterTimeline *timeline);
+ClutterTimeline* clutter_timeline_copy (ClutterTimeline *timeline);
G_END_DECLS
(CLUTTER_MAJOR_VERSION == (major) && CLUTTER_MINOR_VERSION > (minor)) || \
(CLUTTER_MAJOR_VERSION == (major) && CLUTTER_MINOR_VERSION == (minor) && CLUTTER_MICRO_VERSION > (micro)))
+/* GL Windowing system used */
#define CLUTTER_FLAVOUR "@CLUTTER_FLAVOUR@"
+/* cogl backend - gl or gles currently */
+#define CLUTTER_COGL "@CLUTTER_COGL@"
+
+/* Set to 1 if clutter built without FPU (i.e fixed math), 0 otherwise */
+#define CLUTTER_NO_FPU @CLUTTER_NO_FPU@
+
#endif /* __CLUTTER_VERSION_H__ */
#include "clutter-behaviour-path.h"
#include "clutter-behaviour-rotate.h"
#include "clutter-behaviour-scale.h"
+#include "clutter-effect.h"
#include "clutter-stage.h"
#include "clutter-actor.h"
#include "clutter-rectangle.h"
}
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
+ /* FIXME: move to cogl... */
if (!is_gl_version_at_least_12 ())
{
g_set_error (error, CLUTTER_INIT_ERROR,
_clutter_backend_glx_events_init (backend);
}
-static ClutterActor *
+static ClutterActor*
clutter_backend_glx_get_stage (ClutterBackend *backend)
{
ClutterBackendGlx *backend_glx = CLUTTER_BACKEND_GLX (backend);
AC_SUBST(CLUTTER_DEBUG_CFLAGS)
+CLUTTER_NO_FPU=0
+
AC_ARG_WITH(fpu,
AS_HELP_STRING([--without-fpu],
[Assume target hardware has no fpu]),
[with_fpu=yes])
if test "x$with_fpu" != "xyes" ; then
+ CLUTTER_NO_FPU=1
CLUTTER_FIXED_CFLAGS="-DCFX_NO_FPU"
fi
+AC_SUBST(CLUTTER_HAS_FPU)
+
dnl = GTK Doc check ========================================================
GTK_DOC_CHECK([1.4])
-noinst_PROGRAMS = test super-oh behave test-text
+noinst_PROGRAMS = test super-oh behave test-text slider
INCLUDES = -I$(top_srcdir)/
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
+AM_CFLAGS = $(CLUTTER_CFLAGS)
+LDFLAGS = $(CLUTTER_LIBS)
+
+slider_SOURCES = slider.c
+
test_SOURCES = test.c
test_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS)
test_LDFLAGS = \
--- /dev/null
+#include <clutter/clutter.h>
+
+typedef struct Tile
+{
+ ClutterActor *actor;
+ gint orig_pos;
+}
+Tile;
+
+static Tile *Tiles[4][4];
+static int TileW, TileH, BlankTileX, BlankTileY;
+static ClutterEffectTemplate *Template;
+static ClutterTimeline *EffectTimeline;
+
+ClutterActor*
+make_tiles (GdkPixbuf *pixbuf)
+{
+ int x, y , w, h;
+ int i = 0, j = 0;
+ int pos = 0;
+ ClutterActor *group;
+
+ group = clutter_group_new();
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+
+ TileW = w / 4;
+ TileH = h / 4;
+
+ for (y = 0; y < h; y += TileH)
+ {
+ for (x = 0; x < w; x += TileW)
+ {
+ GdkPixbuf *subpixbuf;
+ Tile *tile;
+
+ subpixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
+ 8, TileW, TileH);
+
+ gdk_pixbuf_copy_area (pixbuf, x, y, TileW, TileH,
+ subpixbuf, 0, 0);
+
+ tile = g_slice_new0 (Tile);
+
+ if (pos != 15)
+ {
+ tile->actor = clutter_texture_new_from_pixbuf (subpixbuf);
+ clutter_group_add (CLUTTER_GROUP (group), tile->actor);
+ clutter_actor_set_position (tile->actor, x, y);
+ }
+ else
+ {
+ /* blank tile */
+ tile->actor = NULL;
+ BlankTileX = i;
+ BlankTileY = j;
+ }
+
+ g_object_unref (subpixbuf);
+
+ tile->orig_pos = pos;
+ Tiles[j][i] = tile;
+
+ pos++; i++;
+ }
+ i=0; j++;
+ }
+
+ return group;
+}
+
+static void
+switch_blank_tile (int i, int j)
+{
+ Tile *tmp;
+ ClutterKnot knots[2];
+
+ knots[0].x = i * TileW;
+ knots[0].y = j * TileH;
+
+ knots[1].x = BlankTileX * TileW;
+ knots[1].y = BlankTileY * TileH;
+
+ EffectTimeline = clutter_effect_move (Template,
+ Tiles[j][i]->actor,
+ knots,
+ 2,
+ NULL,
+ NULL);
+
+ /* Add a week pointer to returned timeline so we know whilst its
+ * playing and thus valid.
+ */
+ g_object_add_weak_pointer (G_OBJECT(EffectTimeline),
+ (gpointer*)&EffectTimeline);
+
+ tmp = Tiles[BlankTileY][BlankTileX];
+ Tiles[BlankTileY][BlankTileX] = Tiles[j][i];
+ Tiles[j][i] = tmp;
+
+ BlankTileY = j;
+ BlankTileX = i;
+}
+
+static void
+key_press_event_cb (ClutterStage *stage,
+ ClutterKeyEvent *event,
+ gpointer user_data)
+{
+ Tile *tmp, *tmp2;
+
+ if (clutter_key_event_symbol(event) == CLUTTER_q)
+ clutter_main_quit();
+
+ /* Do move if there is a move already happening */
+ if (EffectTimeline != NULL)
+ return;
+
+ switch (clutter_key_event_symbol(event))
+ {
+ case CLUTTER_Up:
+ if (BlankTileY < 3)
+ switch_blank_tile (BlankTileX, BlankTileY+1);
+ break;
+ case CLUTTER_Down:
+ if (BlankTileY > 0)
+ switch_blank_tile (BlankTileX, BlankTileY-1);
+ break;
+ case CLUTTER_Left:
+ if (BlankTileX < 3)
+ switch_blank_tile (BlankTileX+1, BlankTileY);
+ break;
+ case CLUTTER_Right:
+ if (BlankTileX > 0)
+ switch_blank_tile (BlankTileX-1, BlankTileY);
+ break;
+ default:
+ break;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ GdkPixbuf *pixbuf;
+ ClutterActor *stage, *group;
+ ClutterColor bgcolour;
+
+ /* Initiate clutter */
+ clutter_init (&argc, &argv);
+
+ /* Setup the stage */
+ stage = clutter_stage_get_default ();
+ g_object_set (stage, "fullscreen", TRUE, NULL);
+
+ clutter_color_parse ("#000000", &bgcolour);
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &bgcolour);
+
+ /* Create Tiles */
+ pixbuf = gdk_pixbuf_new_from_file ("image.jpg", NULL);
+ group = make_tiles (pixbuf);
+
+ /* Add to stage and center */
+ clutter_group_add (CLUTTER_GROUP (stage), group);
+ clutter_actor_set_position (group,
+ (clutter_actor_get_width (stage) - clutter_actor_get_width (group)) / 2,
+ (clutter_actor_get_height (stage) - clutter_actor_get_height (group)) / 2);
+
+ /* Link up event collection */
+ g_signal_connect (stage,
+ "key-press-event",
+ G_CALLBACK(key_press_event_cb),
+ NULL);
+
+ /* Template to use for slider animation */
+ Template = clutter_effect_template_new (clutter_timeline_new (15, 60),
+ CLUTTER_ALPHA_RAMP_INC);
+
+ clutter_actor_show_all (stage);
+
+ clutter_main();
+}