2006-11-21 Emmanuele Bassi <ebassi@openedhand.com>
+ * configure.ac: Enable debug messages also when
+ --enable-debug is set to "minimum".
+
+ * clutter/Makefile.am:
+ * clutter/clutter-debug.h: Move all debugging macros inside
+ this private header; make all debug macros depend on the
+ CLUTTER_ENABLE_DEBUG compile time define, controlled by
+ the --enable-debug configure switch; add G_LOG_DOMAIN define.
+
+ * clutter/clutter-main.c: Clean up the debug stuff; add
+ command line argument parsing using GOption; the debug
+ messages now are triggered like this:
+
+ CLUTTER_DEBUG=section:section:... clutter-app
+
+ or like this:
+
+ clutter-app --clutter-debug=section:section:...
+
+ where "section" is one of the sections listed in clutter-main.c,
+ or "all", for all sections; each section is bound to a flag,
+ which can be used to define a domain when adding a debug note
+ using the CLUTTER_NOTE() macro; the old CLUTTER_DBG() macro is
+ just a wrapper around that, under the CLUTTER_DEBUG_MISC domain;
+ CLUTTER_NOTE() is used like this:
+
+ CLUTTER_NOTE (DOMAIN, log-function);
+
+ where log function is g_printerr(), g_message(), g_warning(),
+ g_critical() or directly g_log() - for instance:
+
+ CLUTTER_NOTE (PANGO, g_warning ("Cache miss: %d", glyph));
+
+ will print the warning only if the "pango" flag has been
+ set to the CLUTTER_DEBUG envvar or passed to the --clutter-debug
+ command line argument.
+
+ similar to CLUTTER_SHOW_FPS, there's also the --clutter-show-fps
+ command line switch; also, the --display and --screen command
+ line switches have been added: the first overrides the DISPLAY
+ envvar and the second controls the X screen used by Clutter to
+ get the root window on the display.
+
+ * clutter/clutter-main.h:
+ * clutter/clutter-main.c: Add extended support for GOption
+ in Clutter; use clutter_init_with_args() to let Clutter
+ parse your own command line arguments; use instead
+ clutter_get_option_group() to get the GOptionGroup used by
+ Clutter if you want to do the parsing yourself with
+ g_option_context_parse(). The init sequence has been verified,
+ updated and moved into common functions where possible.
+
+ * clutter/pango/pangoclutter-render.c:
+ * clutter/*.c: Include "clutter-debug.h" where needed; use
+ CLUTTER_NOTE() instead of CLUTTER_DBG().
+
+ * examples/super-oh.c: Use the new clutter_init_with_args()
+ function, and add a --num-hands command line switch to
+ the SuperOH example code controlling the number of hands at
+ runtime.
+
+2006-11-21 Emmanuele Bassi <ebassi@openedhand.com>
+
* configure.ac: Rename G_ENABLE_DEBUG to CLUTTER_ENABLE_DEBUG.
2006-11-20 Emmanuele Bassi <ebassi@openedhand.com>
clutter-media.c \
clutter-enum-types.c
-source_h_priv = clutter-private.h
+source_h_priv = clutter-debug.h clutter-private.h
libclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = $(MARSHALFILES) \
$(source_c) \
-DLIBDIR=\""$(libdir)"\" \
-DDATADIR=\""$(datadir)"\" \
-DG_DISABLE_DEPRECATED \
+ -DG_LOG_DOMAIN=\"Clutter\" \
$(GCC_FLAGS) \
$(CLUTTER_CFLAGS) \
$(CLUTTER_DEBUG_CFLAGS)
if (!CLUTTER_ACTOR_IS_REALIZED (self))
{
- CLUTTER_DBG("@@@ Attempting realize via paint() @@@");
+ CLUTTER_NOTE (PAINT, g_message ("Attempting realize via paint()"));
clutter_actor_realize(self);
if (!CLUTTER_ACTOR_IS_REALIZED (self))
{
- CLUTTER_DBG("*** Attempt failed, aborting paint ***");
+ CLUTTER_NOTE (PAINT, g_warning ("Attempt failed, aborting paint"));
return;
}
}
{
ClutterActor *self = CLUTTER_ACTOR (object);
- CLUTTER_DBG ("Disposing of object (id=%d) of type `%s'",
- self->priv->id,
- g_type_name (G_OBJECT_TYPE (self)));
+ CLUTTER_NOTE (MISC, g_message ("Disposing of object (id=%d) of type `%s'",
+ self->priv->id,
+ g_type_name (G_OBJECT_TYPE (self))));
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION))
{
#include "config.h"
#endif
+#include <math.h>
+
#include "clutter-alpha.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
-#include <math.h>
+#include "clutter-private.h"
+#include "clutter-debug.h"
G_DEFINE_TYPE (ClutterAlpha, clutter_alpha, G_TYPE_OBJECT);
{
ClutterTimeline *timeline;
gint current_frame_num, n_frames;
- gdouble x;
+ gdouble x, sine;
timeline = clutter_alpha_get_timeline (alpha);
/* FIXME: fixed point, and fixed point sine() */
x = (gdouble) (current_frame_num * 2.0f * M_PI) / n_frames ;
+ sine = (sin (x - (M_PI / 2.0f)) + 1.0f) * 0.5f;
- CLUTTER_DBG ("%2f\n", ((sin (x - (M_PI / 2.0f)) + 1.0f) * 0.5f));
+ CLUTTER_NOTE (ALPHA, g_message ("sine: %2f\n", sine));
- return (guint32) (((sin (x - (M_PI / 2.0f)) + 1.0f) * 0.5f)
- * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);
+ return (guint32) (sine * (gdouble) CLUTTER_ALPHA_MAX_ALPHA);
}
#include "clutter-behaviour-opacity.h"
#include "clutter-enum-types.h"
#include "clutter-main.h"
+#include "clutter-private.h"
+#include "clutter-debug.h"
#include <math.h>
opacity += priv->opacity_start;
- CLUTTER_DBG ("alpha %i opacity %i\n", alpha, opacity);
+ CLUTTER_NOTE (BEHAVIOUR, g_message ("alpha %i opacity %i\n",
+ alpha, opacity));
clutter_actor_set_opacity (actor, opacity);
}
CLUTTER_BEHAVIOUR_OPACITY (behave));
}
-static void
-clutter_behaviour_opacity_finalize (GObject *object)
-{
- G_OBJECT_CLASS (clutter_behaviour_opacity_parent_class)->finalize (object);
-}
-
static void
clutter_behaviour_opacity_set_property (GObject *gobject,
guint prop_id,
#include "clutter-main.h"
#include "clutter-fixed.h"
#include "clutter-behaviour-scale.h"
+#include "clutter-private.h"
+#include "clutter-debug.h"
#include <math.h>
case CLUTTER_GRAVITY_WEST:
break;
case CLUTTER_GRAVITY_CENTER:
- CLUTTER_DBG ("%i vs %i\n", sw, w);
+ CLUTTER_NOTE (MISC, g_message (G_STRLOC ": gravity %i vs %i\n", sw, w));
clutter_actor_move_by (actor, sw - w, sh - h);
default:
break;
#include "clutter-feature.h"
#include "clutter-util.h"
#include "clutter-enum-types.h"
-#include "clutter-private.h" /* for DBG */
+#include "clutter-private.h"
+#include "clutter-debug.h"
enum
{
qy1 = y1 + lasty;
qy2 = qy1 + ((qheight * actual_h) / pheight );
- CLUTTER_DBG("rendering text tile x: %i, y: %i - %ix%i",
- x, y, actual_w, actual_h);
+ CLUTTER_NOTE (TEXTURE,
+ g_message ("rendering text tile x: %i, y: %i - %ix%i",
+ x, y,
+ actual_w, actual_h));
glBegin (GL_QUADS);
glTexCoord2f (tx, ty); glVertex2i (qx2, qy2);
clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
- CLUTTER_DBG("paint to x1: %i, y1: %i x2: %i, y2: %i opacity: %i",
- x1, y1, x2, y2, clutter_actor_get_opacity(self) );
+ CLUTTER_NOTE (PAINT, g_message ("paint to x1: %i, y1: %i x2: %i, y2: %i "
+ "opacity: %i",
+ x1, y1, x2, y2,
+ clutter_actor_get_opacity (self)));
/* Parent paint translated us into position */
clone_texture_render_to_gl_quad (CLUTTER_CLONE_TEXTURE(self),
--- /dev/null
+#ifndef __CLUTTER_DEBUG_H__
+#define __CLUTTER_DEBUG_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ CLUTTER_DEBUG_MISC = 1 << 0,
+ CLUTTER_DEBUG_ACTOR = 1 << 1,
+ CLUTTER_DEBUG_TEXTURE = 1 << 2,
+ CLUTTER_DEBUG_EVENT = 1 << 3,
+ CLUTTER_DEBUG_PAINT = 1 << 4,
+ CLUTTER_DEBUG_GL = 1 << 5,
+ CLUTTER_DEBUG_ALPHA = 1 << 6,
+ CLUTTER_DEBUG_BEHAVIOUR = 1 << 7,
+ CLUTTER_DEBUG_PANGO = 1 << 8
+} ClutterDebugFlag;
+
+#ifdef CLUTTER_ENABLE_DEBUG
+
+#define CLUTTER_NOTE(type,action) G_STMT_START { \
+ if (clutter_debug_flags & CLUTTER_DEBUG_##type) \
+ { action; } } G_STMT_END
+
+#define CLUTTER_MARK() CLUTTER_NOTE(MISC, g_message (G_STRLOC ": mark"))
+#define CLUTTER_DBG(x,a...) CLUTTER_NOTE(MISC, g_message (x, ##a))
+
+#define CLUTTER_GLERR() G_STMT_START { \
+ if (clutter_debug_flags & CLUTTER_DEBUG_GL) \
+ { GLenum _err = glGetError (); /* roundtrip */ \
+ if (_err != GL_NO_ERROR) \
+ g_warning (G_STRLOC ": GL Error %x", _err); \
+ } } G_STMT_END
+
+#else /* !CLUTTER_ENABLE_DEBUG */
+
+#define CLUTTER_NOTE(type,action)
+#define CLUTTER_DBG(x,a...)
+#define CLUTTER_GLERR()
+
+#endif /* CLUTTER_ENABLE_DEBUG */
+
+extern guint clutter_debug_flags;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEBUG_H__ */
*/
#include "config.h"
-#include "clutter-main.h"
-#include "clutter-feature.h"
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
- #include <dlfcn.h>
+#include <dlfcn.h>
+
+#include "clutter-feature.h"
+#include "clutter-main.h"
+#include "clutter-private.h"
+#include "clutter-debug.h"
typedef void (*FuncPtr) (void);
typedef int (*GLXGetVideoSyncProc) (unsigned int *count);
if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env("none"))
{
- CLUTTER_DBG("vblank sync: disabled at user request");
+ CLUTTER_NOTE (MISC, g_message ("vblank sync: disabled at user request"));
}
else
{
if (__features->funcs.get_video_sync != NULL
&& __features->funcs.wait_video_sync != NULL)
{
- CLUTTER_DBG("vblank sync: using glx");
- __features->vblank_type = CLUTTER_VBLANK_GLX;
+ CLUTTER_NOTE (MISC, g_message ("vblank sync: using glx"));
+
+ __features->vblank_type = CLUTTER_VBLANK_GLX;
__features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
}
}
__features->dri_fd = open("/dev/dri/card0", O_RDWR);
if (__features->dri_fd >= 0)
{
- CLUTTER_DBG("vblank sync: using dri");
+ CLUTTER_NOTE (MISC, g_message ("vblank sync: using dri"));
+
__features->vblank_type = CLUTTER_VBLANK_DRI;
__features->flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
}
}
if (!(__features->flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
- CLUTTER_DBG("vblank sync: no use-able mechanism found");
+ {
+ CLUTTER_NOTE (MISC,
+ g_message ("vblank sync: no use-able mechanism found"));
+ }
}
}
#include "clutter-label.h"
#include "clutter-main.h"
#include "clutter-enum-types.h"
-#include "clutter-private.h" /* for DBG */
+#include "clutter-private.h"
+#include "clutter-debug.h"
#include "pangoclutter.h"
if (priv->desc == NULL || priv->text == NULL)
{
- CLUTTER_DBG("*** FAIL: layout: %p , desc: %p, text %p ***",
- priv->layout, priv->desc, priv->text);
+ CLUTTER_NOTE (ACTOR, g_warning ("layout: %p , desc: %p, text %p",
+ priv->layout,
+ priv->desc,
+ priv->text));
return;
}
* functions for mainloops, events and threads
*/
-
+#ifdef HAVE_CONFIG_H
#include "config.h"
+#endif
#include <stdlib.h>
#include "clutter-actor.h"
#include "clutter-stage.h"
#include "clutter-private.h"
+#include "clutter-debug.h"
+
+static gboolean clutter_is_initialized = FALSE;
+static gboolean clutter_show_fps = FALSE;
+static gchar *clutter_display_name = NULL;
+static int clutter_screen = 0;
+
+guint clutter_debug_flags = 0; /* global clutter debug flag */
+
+#ifdef CLUTTER_ENABLE_DEBUG
+static const GDebugKey clutter_debug_keys[] = {
+ { "misc", CLUTTER_DEBUG_MISC },
+ { "actor", CLUTTER_DEBUG_ACTOR },
+ { "texture", CLUTTER_DEBUG_TEXTURE },
+ { "event", CLUTTER_DEBUG_EVENT },
+ { "paint", CLUTTER_DEBUG_PAINT },
+ { "gl", CLUTTER_DEBUG_GL },
+ { "alpha", CLUTTER_DEBUG_ALPHA },
+ { "behaviour", CLUTTER_DEBUG_BEHAVIOUR },
+ { "pango", CLUTTER_DEBUG_PANGO },
+};
+#endif /* CLUTTER_ENABLE_DEBUG */
typedef struct
{
typedef void (*ClutterXEventFunc) (XEvent *xev, gpointer user_data);
-static gboolean __clutter_has_debug = FALSE;
-static gboolean __clutter_has_fps = FALSE;
-
static ClutterMainContext *ClutterCntx = NULL;
static gboolean
translate_key_event (ClutterKeyEvent *event,
XEvent *xevent)
{
- event->type = xevent->xany.type
- == KeyPress ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE;
+ event->type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
+ : CLUTTER_KEY_RELEASE;
event->time = xevent->xkey.time;
event->modifier_state = xevent->xkey.state; /* FIXME: handle modifiers */
event->hardware_keycode = xevent->xkey.keycode;
XEvent *xevent)
{
/* FIXME: catch double click */
- CLUTTER_DBG("button event at %ix%i", xevent->xbutton.x, xevent->xbutton.y);
+ CLUTTER_NOTE (EVENT, g_message (G_STRLOC ": button event at %ix%i",
+ xevent->xbutton.x,
+ xevent->xbutton.y));
- event->type = xevent->xany.type
- == ButtonPress ? CLUTTER_BUTTON_PRESS : CLUTTER_BUTTON_RELEASE;
+ event->type = xevent->xany.type == ButtonPress ? CLUTTER_BUTTON_PRESS
+ : CLUTTER_BUTTON_RELEASE;
event->time = xevent->xbutton.time;
event->x = xevent->xbutton.x;
event->y = xevent->xbutton.y;
/* FIXME: need to make stage an 'actor' so can que
* a paint direct from there rather than hack here...
- */
+ */
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
}
break;
}
static gboolean
-clutter_want_fps(void)
+clutter_want_fps (void)
{
- return __clutter_has_fps;
+ return clutter_show_fps;
}
/**
/* FIXME: Should move all this into stage...
*/
- CLUTTER_DBG("@@@ Redraw enter @@@");
+ CLUTTER_NOTE (PAINT, g_message (G_STRLOC ": Redraw enter"));
if (clutter_want_fps ())
{
}
}
- CLUTTER_DBG("@@@ Redraw leave @@@");
+ CLUTTER_NOTE (PAINT, g_message (G_STRLOC ": Redraw leave"));
}
/**
ClutterMainContext *context = CLUTTER_CONTEXT ();
GMainLoop *loop;
- if (!context->is_initialized)
+ if (!clutter_is_initialized)
{
g_warning ("Called clutter_main() but Clutter wasn't initialised. "
"You must call clutter_init() first.");
gboolean
clutter_want_debug (void)
{
- return __clutter_has_debug;
+ return clutter_debug_flags != 0;
}
ClutterMainContext*
const gchar *version;
gint i = 0;
- version = (const gchar*)glGetString(GL_VERSION);
+ version = (const gchar*) glGetString (GL_VERSION);
while ( ((version[i] <= '9' && version[i] >= '0') || version[i] == '.')
&& i < NON_VENDOR_VERSION_MAX_LEN)
}
-/**
- * clutter_init:
- * @argc: The number of arguments in @argv
- * @argv: A pointer to an array of arguments.
- *
- * Initialises Clutter.
- *
- * Return value: 1 on success, < 0 on failure.
- */
-ClutterInitError
-clutter_init (int *argc, char ***argv)
+#ifdef CLUTTER_ENABLE_DEBUG
+static gboolean
+clutter_arg_debug_cb (const char *key,
+ const char *value,
+ gpointer user_data)
{
- ClutterMainContext *context;
- static gboolean is_initialized = FALSE;
-
- if (is_initialized)
- return CLUTTER_INIT_SUCCESS;
+ clutter_debug_flags |=
+ g_parse_debug_string (value,
+ clutter_debug_keys,
+ G_N_ELEMENTS (clutter_debug_keys));
+ return TRUE;
+}
- context = clutter_context_get_default ();
+static gboolean
+clutter_arg_no_debug_cb (const char *key,
+ const char *value,
+ gpointer user_data)
+{
+ clutter_debug_flags &=
+ ~g_parse_debug_string (value,
+ clutter_debug_keys,
+ G_N_ELEMENTS (clutter_debug_keys));
+ return TRUE;
+}
+#endif /* CLUTTER_ENABLE_DEBUG */
+
+static GOptionEntry clutter_args[] = {
+ { "display", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &clutter_display_name,
+ "X display to use", "DISPLAY" },
+ { "screen", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &clutter_screen,
+ "X screen to use", "SCREEN" },
+ { "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
+ "Show frames per second", NULL },
+#ifdef CLUTTER_ENABLE_DEBUG
+ { "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
+ "Clutter debugging flags to set", "FLAGS" },
+ { "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb,
+ "Clutter debugging flags to unset", "FLAGS" },
+#endif /* CLUTTER_ENABLE_DEBUG */
+ { NULL, },
+};
- if (g_getenv ("CLUTTER_DEBUG"))
- __clutter_has_debug = TRUE;
+/* pre_parse_hook: initialise variables depending on environment
+ * variables; these variables might be overridden by the command
+ * line arguments that are going to be parsed after.
+ */
+static gboolean
+pre_parse_hook (GOptionContext *context,
+ GOptionGroup *group,
+ gpointer data,
+ GError **error)
+{
+ const char *env_string;
- if (g_getenv ("CLUTTER_SHOW_FPS"))
- __clutter_has_fps = TRUE;
+ if (clutter_is_initialized)
+ return TRUE;
- g_type_init();
+ g_type_init ();
if (!g_thread_supported ())
g_thread_init (NULL);
- if (!XInitThreads())
- return CLUTTER_INIT_ERROR_THREADS;
+#ifdef CLUTTER_ENABLE_DEBUG
+ env_string = g_getenv ("CLUTTER_DEBUG");
+ if (env_string != NULL)
+ {
+ clutter_debug_flags =
+ g_parse_debug_string (env_string,
+ clutter_debug_keys,
+ G_N_ELEMENTS (clutter_debug_keys));
+ env_string = NULL;
+ }
+#endif /* CLUTTER_ENABLE_DEBUG */
- context->main_loops = NULL;
- context->main_loop_level = 0;
+ env_string = g_getenv ("CLUTTER_SHOW_FPS");
+ if (env_string)
+ clutter_show_fps = TRUE;
- if ((context->xdpy = XOpenDisplay (g_getenv ("DISPLAY"))) == NULL)
+ env_string = g_getenv ("DISPLAY");
+ if (env_string)
+ clutter_display_name = g_strdup (env_string);
+
+ return TRUE;
+}
+
+/* post_parse_hook: initialise the context and data structures
+ * and opens the X display
+ */
+static gboolean
+post_parse_hook (GOptionContext *context,
+ GOptionGroup *group,
+ gpointer data,
+ GError **error)
+{
+ ClutterMainContext *clutter_context;
+
+ clutter_context = clutter_context_get_default ();
+ clutter_context->main_loops = NULL;
+ clutter_context->main_loop_level = 0;
+
+ /* either we got this with the DISPLAY envvar or via the
+ * --display command line switch; if both failed, then
+ * we'll fail later when we return in clutter_init()
+ */
+ if (clutter_display_name)
+ clutter_context->xdpy = XOpenDisplay (clutter_display_name);
+
+ if (clutter_context->xdpy)
{
- g_critical ("Unable to connect to X DISPLAY.");
- return CLUTTER_INIT_ERROR_DISPLAY;
+ if (clutter_screen == 0)
+ clutter_context->xscreen = DefaultScreen (clutter_context->xdpy);
+ else
+ {
+ Screen *xscreen;
+
+ xscreen = ScreenOfDisplay (clutter_context->xdpy, clutter_screen);
+ clutter_context->xscreen = XScreenNumberOfScreen (xscreen);
+ }
+
+ clutter_context->xwin_root = RootWindow (clutter_context->xdpy,
+ clutter_context->xscreen);
+
+ /* we don't need it anymore */
+ g_free (clutter_display_name);
}
- context->xscreen = DefaultScreen(context->xdpy);
- context->xwin_root = RootWindow(context->xdpy,
- context->xscreen);
+ clutter_context->font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ());
+ pango_ft2_font_map_set_resolution (clutter_context->font_map, 96.0, 96.0);
- context->font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ());
- pango_ft2_font_map_set_resolution (context->font_map, 96.0, 96.0);
+ clutter_context->gl_lock = g_mutex_new ();
+
+ clutter_is_initialized = TRUE;
+
+ return TRUE;
+}
+
+/**
+ * clutter_get_option_group:
+ *
+ * Returns a #GOptionGroup for the command line arguments recognized
+ * by Clutter. You should add this group to your #GOptionContext with
+ * g_option_context_add_group(), if you are using g_option_context_parse()
+ * to parse your commandline arguments.
+ *
+ * Return value: a GOptionGroup for the commandline arguments
+ * recognized by Clutter
+ *
+ * Since: 0.2
+ */
+GOptionGroup *
+clutter_get_option_group (void)
+{
+ GOptionGroup *group;
- context->gl_lock = g_mutex_new ();
+ group = g_option_group_new ("clutter",
+ "Clutter Options",
+ "Show Clutter Options",
+ NULL,
+ NULL);
+ g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
+ g_option_group_add_entries (group, clutter_args);
+
+ return group;
+}
+
+static gboolean
+clutter_parse_args (int *argc,
+ char ***argv)
+{
+ GOptionContext *option_context;
+ GOptionGroup *clutter_group;
+ GError *error = NULL;
+
+ if (clutter_is_initialized)
+ return TRUE;
+
+ option_context = g_option_context_new (NULL);
+ g_option_context_set_ignore_unknown_options (option_context, TRUE);
+ g_option_context_set_help_enabled (option_context, FALSE);
+
+ clutter_group = clutter_get_option_group ();
+ g_option_context_set_main_group (option_context, clutter_group);
+ if (!g_option_context_parse (option_context, argc, argv, &error))
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_option_context_free (option_context);
+
+ return TRUE;
+}
+
+GQuark
+clutter_init_error_quark (void)
+{
+ return g_quark_from_static_string ("clutter-init-error-quark");
+}
+static gboolean
+clutter_stage_init (ClutterMainContext *context,
+ GError **error)
+{
context->stage = CLUTTER_STAGE (clutter_stage_get_default ());
- g_return_val_if_fail (CLUTTER_IS_STAGE (context->stage), -3);
+ if (!CLUTTER_IS_STAGE (context->stage))
+ {
+ g_set_error (error, clutter_init_error_quark (),
+ CLUTTER_INIT_ERROR_INTERNAL,
+ "Unable to create the main stage");
+ return FALSE;
+ }
+
g_object_ref_sink (context->stage);
/* Realize to get context */
clutter_actor_realize (CLUTTER_ACTOR (context->stage));
+ if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (context->stage)))
+ {
+ g_set_error (error, clutter_init_error_quark (),
+ CLUTTER_INIT_ERROR_INTERNAL,
+ "Unable to realize the main stage");
+ return FALSE;
+ }
+
+ return TRUE;
+}
- g_return_val_if_fail
- (CLUTTER_ACTOR_IS_REALIZED(CLUTTER_ACTOR(context->stage)),
- CLUTTER_INIT_ERROR_INTERNAL);
+/**
+ * clutter_init_with_args:
+ * @argc: a pointer to the number of command line arguments
+ * @argv: a pointer to the array of comman line arguments
+ * @parameter_string: a string which is displayed in the
+ * first line of <option>--help</option> output, after
+ * <literal><replaceable>programname</replaceable [OPTION...]</literal>
+ * @entries: a %NULL terminated array of #GOptionEntry<!-- -->s
+ * describing the options of your program
+ * @translation_domain: a translation domain to use for translating
+ * the <option>--help</option> output for the options in @entries
+ * with gettext(), or %NULL
+ * @error: a return location for a #GError
+ *
+ * This function does the same work as clutter_init(). Additionally,
+ * it allows you to add your own command line options, and it
+ * automatically generates nicely formatted <option>--help</option>
+ * output. Note that your program will be terminated after writing
+ * out the help output. Also note that, in case of error, the
+ * error message will be placed inside @error instead of being
+ * printed on the display.
+ *
+ * Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully
+ * initialised, or other values or #ClutterInitError in case of
+ * error.
+ *
+ * Since: 0.2
+ */
+ClutterInitError
+clutter_init_with_args (int *argc,
+ char ***argv,
+ char *parameter_string,
+ GOptionEntry *entries,
+ char *translation_domain,
+ GError **error)
+{
+ ClutterMainContext *clutter_context;
+ GOptionContext *context;
+ GOptionGroup *group;
+ gboolean res;
+ GError *stage_error;
+
+ if (clutter_is_initialized)
+ return CLUTTER_INIT_SUCCESS;
+
+ if (!XInitThreads())
+ {
+ g_set_error (error, clutter_init_error_quark (),
+ CLUTTER_INIT_ERROR_THREADS,
+ "Unable to initialise the X threading");
+ return CLUTTER_INIT_ERROR_THREADS;
+ }
+
+ group = clutter_get_option_group ();
+
+ context = g_option_context_new (parameter_string);
+ g_option_context_add_group (context, group);
+
+ if (entries)
+ g_option_context_add_main_entries (context, entries, translation_domain);
+
+ res = g_option_context_parse (context, argc, argv, error);
+ g_option_context_free (context);
+
+ /* if res is FALSE, the error is filled for
+ * us by g_option_context_parse()
+ */
+ if (!res)
+ return CLUTTER_INIT_ERROR_INTERNAL;
+
+ clutter_context = clutter_context_get_default ();
+ if (!clutter_context->xdpy)
+ {
+ g_set_error (error, clutter_init_error_quark (),
+ CLUTTER_INIT_ERROR_DISPLAY,
+ "Unable to connect to X DISPLAY. You should either "
+ "set the DISPLAY environment variable or use the "
+ "--display command line switch");
+ return CLUTTER_INIT_ERROR_DISPLAY;
+ }
+
+ stage_error = NULL;
+ if (!clutter_stage_init (clutter_context, &stage_error))
+ {
+ g_propagate_error (error, stage_error);
+ return CLUTTER_INIT_ERROR_INTERNAL;
+ }
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
- g_return_val_if_fail(is_gl_version_at_least_12 (),
- CLUTTER_INIT_ERROR_OPENGL);
+ if (!is_gl_version_at_least_12 ())
+ {
+ g_set_error (error, clutter_init_error_quark (),
+ CLUTTER_INIT_ERROR_OPENGL,
+ "Clutter needs at least version 1.2 of OpenGL");
+ return CLUTTER_INIT_ERROR_OPENGL;
+ }
/* Check available features */
clutter_feature_init ();
events_init ();
+ return CLUTTER_INIT_SUCCESS;
+}
- context->is_initialized = TRUE;
+/**
+ * clutter_init:
+ * @argc: The number of arguments in @argv
+ * @argv: A pointer to an array of arguments.
+ *
+ * It will initialise everything needed to operate with Clutter and
+ * parses some standard command line options. @argc and @argv are
+ * adjusted accordingly so your own code will never see those standard
+ * arguments.
+ *
+ * Return value: 1 on success, < 0 on failure.
+ */
+ClutterInitError
+clutter_init (int *argc,
+ char ***argv)
+{
+ ClutterMainContext *context;
+ GError *stage_error;
+
+ if (clutter_is_initialized)
+ return CLUTTER_INIT_SUCCESS;
+
+ if (!XInitThreads())
+ return CLUTTER_INIT_ERROR_THREADS;
+
+ clutter_parse_args (argc, argv);
+
+ context = clutter_context_get_default ();
+ if (!context->xdpy)
+ {
+ g_critical ("Unable to connect to X DISPLAY. You should either "
+ "set the DISPLAY environment variable or use the "
+ "--display command line switch");
+
+ return CLUTTER_INIT_ERROR_DISPLAY;
+ }
+
+ stage_error = NULL;
+ if (!clutter_stage_init (context, &stage_error))
+ {
+ g_critical (stage_error->message);
+ g_error_free (stage_error);
+ return CLUTTER_INIT_ERROR_INTERNAL;
+ }
+
+ /* At least GL 1.2 is needed for CLAMP_TO_EDGE */
+ if (!is_gl_version_at_least_12 ())
+ {
+ g_critical ("Clutter needs at least version 1.2 of OpenGL");
+ return CLUTTER_INIT_ERROR_OPENGL;
+ }
+
+ /* Check available features */
+ clutter_feature_init ();
+
+ events_init ();
return 1;
}
-
G_BEGIN_DECLS
-#define CLUTTER_HAS_DEBUG_MESSGES 1
-
-#if (CLUTTER_HAS_DEBUG_MESSGES)
-
-#define CLUTTER_DBG(x, a...) \
- if (clutter_want_debug()) \
- { g_printerr ( __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a); }
-
-#define CLUTTER_GLERR() \
- if (clutter_want_debug()) \
- { \
- GLenum err = glGetError (); /* Roundtrip */ \
- if (err != GL_NO_ERROR) \
- { \
- g_printerr (__FILE__ ": GL Error: %x [at %s:%d]\n", \
- err, __func__, __LINE__); \
- } \
- }
-#else
-#define CLUTTER_DBG(x, a...) do {} while (0)
-#define CLUTTER_GLERR() do {} while (0)
-#endif /* CLUTTER_HAS_DEBUG */
-
-#define CLUTTER_MARK() CLUTTER_DBG("mark")
+#define CLUTTER_INIT_ERROR (clutter_init_error_quark ())
typedef enum {
CLUTTER_INIT_SUCCESS = 1,
CLUTTER_INIT_ERROR_OPENGL = -4
} ClutterInitError;
-ClutterInitError
-clutter_init (int *argc, char ***argv);
-
-void
-clutter_main (void);
-
-void
-clutter_main_quit (void);
-
-gint
-clutter_main_level (void);
-
-void
-clutter_redraw ();
-
-Display*
-clutter_xdisplay (void);
-
-int
-clutter_xscreen (void);
-
-Window
-clutter_root_xwindow (void);
-
-gboolean
-clutter_want_debug (void);
-
-void
-clutter_threads_enter (void);
-
-void
-clutter_threads_leave (void);
+GQuark clutter_init_error_quark (void);
+
+ClutterInitError clutter_init (int *argc,
+ char ***argv);
+ClutterInitError clutter_init_with_args (int *argc,
+ char ***argv,
+ char *parameter_string,
+ GOptionEntry *entries,
+ char *translation_domain,
+ GError **error);
+
+GOptionGroup * clutter_get_option_group (void);
+
+void clutter_main (void);
+void clutter_main_quit (void);
+gint clutter_main_level (void);
+void clutter_redraw (void);
+Display * clutter_xdisplay (void);
+gint clutter_xscreen (void);
+Window clutter_root_xwindow (void);
+gboolean clutter_want_debug (void);
+void clutter_threads_enter (void);
+void clutter_threads_leave (void);
G_END_DECLS
#include <pango/pangoft2.h>
+#include <clutter/clutter-debug.h>
G_BEGIN_DECLS
#include "clutter-util.h"
#include "clutter-marshal.h"
#include "clutter-enum-types.h"
-#include "clutter-private.h" /* for DBG */
+#include "clutter-private.h"
+#include "clutter-debug.h"
#include <GL/glx.h>
#include <GL/gl.h>
glXMakeCurrent(clutter_xdisplay(), priv->xwin, priv->gl_context);
}
- CLUTTER_DBG("===========================================")
- CLUTTER_DBG("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
- CLUTTER_DBG("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
- CLUTTER_DBG("GL_VERSION: %s\n", glGetString(GL_VERSION));
- CLUTTER_DBG("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
- CLUTTER_DBG("===========================================")
+ CLUTTER_NOTE (GL,
+ g_message ("\n"
+ "==========================================="
+ "GL_VENDOR: %s\n"
+ "GL_RENDERER: %s\n"
+ "GL_VERSION: %s\n"
+ "GL_EXTENSIONS: %s\n"
+ "===========================================",
+ glGetString (GL_VENDOR),
+ glGetString (GL_RENDERER),
+ glGetString (GL_VERSION),
+ glGetString (GL_EXTENSIONS)));
sync_gl_viewport (stage);
}
#include "clutter-marshal.h"
#include "clutter-feature.h"
#include "clutter-util.h"
-#include "clutter-private.h" /* for DBG */
+#include "clutter-private.h"
+#include "clutter-debug.h"
#include <GL/glx.h>
#include <GL/gl.h>
{
GLint new_width = 0;
- CLUTTER_DBG("checking %ix%i", width, height);
+ CLUTTER_NOTE (TEXTURE, g_message ("checking %ix%i", width, height));
glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA,
width, height, 0 /* border */,
&& (x_pot - priv->width < priv->max_tile_waste)
&& (y_pot - priv->height < priv->max_tile_waste)))
{
- CLUTTER_DBG("x_pot:%i - width:%i < max_waste:%i",
- x_pot, priv->width, priv->max_tile_waste);
+ CLUTTER_NOTE (TEXTURE, g_message ("x_pot:%i - width:%i < max_waste:%i",
+ x_pot,
+ priv->width,
+ priv->max_tile_waste));
- CLUTTER_DBG("y_pot:%i - height:%i < max_waste:%i",
- y_pot, priv->height, priv->max_tile_waste);
+ CLUTTER_NOTE (TEXTURE, g_message ("y_pot:%i - height:%i < max_waste:%i",
+ y_pot,
+ priv->height,
+ priv->max_tile_waste));
if (x_pot > y_pot)
x_pot /= 2;
priv->y_tiles = g_new (ClutterTextureTileDimention, priv->n_y_tiles);
tile_dimension (priv->height, y_pot, priv->max_tile_waste, priv->y_tiles);
- CLUTTER_DBG("x_pot:%i, width:%i, y_pot:%i, height: %i max_waste:%i, "
- " n_x_tiles: %i, n_y_tiles: %i",
- x_pot, priv->width, y_pot, priv->height, priv->max_tile_waste,
- priv->n_x_tiles, priv->n_y_tiles);
+ CLUTTER_NOTE (TEXTURE,
+ g_message ("x_pot:%i, width:%i, y_pot:%i, height: %i "
+ "max_waste:%i, n_x_tiles: %i, n_y_tiles: %i",
+ x_pot, priv->width, y_pot, priv->height,
+ priv->max_tile_waste,
+ priv->n_x_tiles, priv->n_y_tiles));
}
actual_w = priv->x_tiles[x].size - priv->x_tiles[x].waste;
actual_h = priv->y_tiles[y].size - priv->y_tiles[y].waste;
- CLUTTER_DBG("rendering text tile x: %i, y: %i - %ix%i",
- x, y, actual_w, actual_h);
+ CLUTTER_NOTE (TEXTURE,
+ g_message ("rendering text tile x: %i, y: %i - %ix%i",
+ x, y, actual_w, actual_h));
tx = (float) actual_w / priv->x_tiles[x].size;
ty = (float) actual_h / priv->y_tiles[y].size;
create_textures = TRUE;
}
- CLUTTER_DBG("syncing for single tile");
+ CLUTTER_NOTE (TEXTURE, g_message ("syncing for single tile"));
glBindTexture(priv->target_type, priv->tiles[0]);
/* Multiple tiled texture */
- CLUTTER_DBG("syncing for multiple tiles for %ix%i pixbuf",
- priv->width, priv->height);
+ CLUTTER_NOTE (TEXTURE,
+ g_message ("syncing for multiple tiles for %ix%i pixbuf",
+ priv->width, priv->height));
g_return_if_fail (priv->x_tiles != NULL && priv->y_tiles != NULL);
src_h = priv->height - priv->y_tiles[y].pos;
}
- CLUTTER_DBG("copying tile %i,%i - %ix%i to 0,0 %ix%i",
- priv->x_tiles[x].pos,
- priv->y_tiles[y].pos,
- src_w,
- src_h,
- priv->x_tiles[x].size,
- priv->y_tiles[y].size);
+ CLUTTER_NOTE (TEXTURE,
+ g_message ("copying tile %i,%i - %ix%i to 0,0 %ix%i",
+ priv->x_tiles[x].pos, priv->y_tiles[y].pos,
+ src_w, src_h,
+ priv->x_tiles[x].size,
+ priv->y_tiles[y].size));
for (dy = 0; dy < src_h; dy++)
{
texture_free_gl_resources (texture);
- CLUTTER_DBG("Texture unrealized");
+ CLUTTER_NOTE (TEXTURE, g_message ("Texture unrealized"));
}
static void
/* Dont allow realization with no pixbuf - note set_pixbuf/data
* will set realize flags.
*/
- CLUTTER_DBG("*** Texture has no image data cannot realize ***");
- CLUTTER_DBG("*** flags %i ***", actor->flags);
+ CLUTTER_NOTE (TEXTURE,
+ g_warning ("Texture has no image data cannot realize"));
+
+ CLUTTER_NOTE (TEXTURE, g_message ("flags %i", actor->flags));
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
- CLUTTER_DBG("*** flags %i ***", actor->flags);
+ CLUTTER_NOTE (TEXTURE, g_message ("flags %i", actor->flags));
return;
}
- CLUTTER_DBG("Texture realized");
+ CLUTTER_NOTE (TEXTURE, g_message ("Texture realized"));
}
static void
gint x1, y1, x2, y2;
guint8 opacity;
- CLUTTER_DBG("@@@ for '%s' @@@",
- clutter_actor_get_name(self) ?
- clutter_actor_get_name(self) : "unknown");
+ CLUTTER_NOTE (PAINT,
+ g_message ("@@@ for '%s' @@@",
+ clutter_actor_get_name (self) ? clutter_actor_get_name (self)
+ : "unknown"));
glPushMatrix();
glEnable(GL_BLEND);
opacity = clutter_actor_get_opacity(self);
- CLUTTER_DBG("setting opacity to %i\n", opacity);
+ CLUTTER_NOTE (PAINT, g_message ("setting opacity to %i\n", opacity));
glColor4ub(255, 255, 255, opacity);
clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
&& priv->tiled == TRUE)
priv->target_type = GL_TEXTURE_2D;
- CLUTTER_DBG("Texture is tiled ? %i", priv->tiled);
+ CLUTTER_NOTE (TEXTURE, g_message ("Texture is tiled ? %s",
+ priv->tiled ? "yes" : "no"));
break;
case PROP_MAX_TILE_WASTE:
priv->max_tile_waste = g_value_get_int (value);
texture_init_tiles (texture);
}
- CLUTTER_DBG("set size %ix%i\n", priv->width, priv->height);
+ CLUTTER_NOTE (TEXTURE, g_message ("set size %ix%i\n",
+ priv->width,
+ priv->height));
texture_upload_data (texture, data, has_alpha,
width, height, rowstride, bpp);
#include "clutter-timeline.h"
#include "clutter-main.h"
-#include "clutter-private.h" /* for DBG */
#include "clutter-marshal.h"
+#include "clutter-private.h"
+#include "clutter-debug.h"
G_DEFINE_TYPE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT);
-#define FPS_TO_INTERVAL(f) (1000/f)
+#define FPS_TO_INTERVAL(f) (1000 / (f))
struct _ClutterTimelinePrivate
{
n_frames = 1;
if (n_frames > 1)
- CLUTTER_DBG("*** Skipping %i frames ***", n_frames);
+ CLUTTER_NOTE (MISC, g_message ("Skipping %i frames", n_frames));
}
else
{
* Boston, MA 02111-1307, USA.
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <math.h>
#include "pangoclutter.h"
#include "pangoclutter-private.h"
+#include "../clutter-debug.h"
/*
* Texture cache support code
/* create a new texture if necessary */
if (!match)
{
- CLUTTER_DBG("creating new texture %i x %i\n", TC_WIDTH, TC_HEIGHT);
+ CLUTTER_NOTE (PANGO, g_message ("creating new texture %i x %i\n",
+ TC_WIDTH, TC_HEIGHT));
match = g_slice_new (tc_texture);
match->next = first_texture;
g->left = bm.left;
g->top = bm.top;
- CLUTTER_DBG("cache fail; subimage2d %i\n", glyph);
+ CLUTTER_NOTE (PANGO, g_message ("cache fail; subimage2d %i\n", glyph));
glBindTexture (GL_TEXTURE_2D, g->tex.name);
glPixelStorei (GL_UNPACK_ROW_LENGTH, bm.stride);
renderer->curtex = g->tex.name;
glBegin (GL_QUADS);
}
- else CLUTTER_DBG("cache succsess %i\n", glyph);
+ else CLUTTER_NOTE (PANGO, g_message ("cache succsess %i\n", glyph));
x += g->left;
y -= g->top;
if test "x$enable_debug" = "xno"; then
CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS -DG_DISABLE_CAST
_CHECKS"
- else
- CLUTTER_DEBUG_CFLAGS="-DG_DISABLE_CAST_CHECKS"
+ else # minimum
+ CLUTTER_DEBUG_CFLAGS="-DG_ENABLE_DEBUG -DG_DISABLE_CAST_CHECKS"
fi
fi
# Header files to ignore when scanning.
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=\
+ clutter-debug.h \
clutter-private.h \
clutter-marshal.h \
clutter-keysyms.h \
clutter_want_debug
clutter_threads_enter
clutter_threads_leave
-<SUBSECTION Private>
-CLUTTER_HAS_DEBUG_MESSGES
-CLUTTER_DBG
-CLUTTER_GLERR
-CLUTTER_MARK
</SECTION>
<SECTION>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
+#include <glib.h>
#define TRAILS 0
#define NHANDS 6
-#define RADIUS ((CLUTTER_STAGE_WIDTH()+CLUTTER_STAGE_HEIGHT())/6)
+#define RADIUS ((CLUTTER_STAGE_WIDTH()+CLUTTER_STAGE_HEIGHT())/NHANDS)
typedef struct SuperOH
{
- ClutterActor *hand[NHANDS], *bgtex;
+ ClutterActor **hand, *bgtex;
ClutterActor *group;
GdkPixbuf *bgpixb;
} SuperOH;
+static gint n_hands = NHANDS;
+
+static GOptionEntry super_oh_entries[] = {
+ {
+ "num-hands", 'n',
+ 0,
+ G_OPTION_ARG_INT, &n_hands,
+ "Number of hands", "HANDS"
+ },
+ { NULL }
+};
+
+static gint
+get_radius (void)
+{
+ return (CLUTTER_STAGE_WIDTH() + CLUTTER_STAGE_HEIGHT()) / n_hands;
+}
+
void
screensaver_setup (void)
{
#endif
/* Rotate everything clockwise about stage center*/
- clutter_actor_rotate_z (CLUTTER_ACTOR(oh->group),
- frame_num,
- CLUTTER_STAGE_WIDTH()/2,
- CLUTTER_STAGE_HEIGHT()/2);
- for (i = 0; i < NHANDS; i++)
+ clutter_actor_rotate_z (CLUTTER_ACTOR (oh->group),
+ frame_num,
+ CLUTTER_STAGE_WIDTH() / 2,
+ CLUTTER_STAGE_HEIGHT() / 2);
+ for (i = 0; i < n_hands; i++)
{
/* rotate each hand around there centers */
clutter_actor_rotate_z (oh->hand[i],
- - 6.0 * frame_num,
- clutter_actor_get_width (oh->hand[i])/2,
- clutter_actor_get_height (oh->hand[i])/2);
+ - 6.0 * frame_num,
+ clutter_actor_get_width (oh->hand[i]) / 2,
+ clutter_actor_get_height (oh->hand[i]) / 2);
}
/*
GdkPixbuf *pixbuf;
SuperOH *oh;
gint i;
+ GError *error;
+
+ error = NULL;
+ clutter_init_with_args (&argc, &argv,
+ NULL,
+ super_oh_entries,
+ NULL,
+ &error);
+ if (error)
+ {
+ g_warning ("Unable to initialise Clutter:\n%s",
+ error->message);
+ g_error_free (error);
- clutter_init (&argc, &argv);
+ exit (1);
+ }
stage = clutter_stage_get_default ();
/* create a new group to hold multiple actors in a group */
oh->group = clutter_group_new();
-
- for (i = 0; i < NHANDS; i++)
+
+ oh->hand = g_new (ClutterActor*, n_hands);
+ for (i = 0; i < n_hands; i++)
{
gint x, y, w, h;
+ gint radius = get_radius ();
/* Create a texture from pixbuf, then clone in to same resources */
if (i == 0)
w = clutter_actor_get_width (oh->hand[0]);
h = clutter_actor_get_height (oh->hand[0]);
- x = CLUTTER_STAGE_WIDTH() / 2
- + RADIUS * cos (i * M_PI / (NHANDS/2)) - w/2;
- y = CLUTTER_STAGE_HEIGHT() / 2
- + RADIUS * sin (i * M_PI / (NHANDS/2)) - h/2;
+ x = CLUTTER_STAGE_WIDTH () / 2
+ + radius
+ * cos (i * M_PI / (n_hands / 2))
+ - w / 2;
+ y = CLUTTER_STAGE_HEIGHT () / 2
+ + radius
+ * sin (i * M_PI / (n_hands / 2))
+ - h / 2;
clutter_actor_set_position (oh->hand[i], x, y);
g_object_set(timeline, "loop", TRUE, 0); /* have it loop */
/* fire a callback for frame change */
- g_signal_connect(timeline, "new-frame", G_CALLBACK (frame_cb), oh);
+ g_signal_connect (timeline, "new-frame",
+ G_CALLBACK (frame_cb), oh);
/* and start it */
clutter_timeline_start (timeline);
clutter_main();
+ g_free (oh->hand);
+ g_free (oh);
+
return 0;
}