4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006 OpenedHand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
26 * SECTION:clutter-main
27 * @short_description: Various 'global' clutter functions.
29 * Functions to retrieve various global Clutter resources and other utility
30 * functions for mainloops, events and threads
38 #include <glib/gi18n-lib.h>
42 #include <gdk-pixbuf/gdk-pixbuf.h>
45 #include "clutter-event.h"
46 #include "clutter-backend.h"
47 #include "clutter-main.h"
48 #include "clutter-master-clock.h"
49 #include "clutter-feature.h"
50 #include "clutter-actor.h"
51 #include "clutter-stage.h"
52 #include "clutter-private.h"
53 #include "clutter-debug.h"
54 #include "clutter-version.h" /* For flavour define */
55 #include "clutter-frame-source.h"
57 #include "cogl/cogl.h"
58 #include "pango/cogl-pango.h"
61 static ClutterMainContext *ClutterCntx = NULL;
63 /* main lock and locking/unlocking functions */
64 static GMutex *clutter_threads_mutex = NULL;
65 static GCallback clutter_threads_lock = NULL;
66 static GCallback clutter_threads_unlock = NULL;
68 /* command line options */
69 static gboolean clutter_is_initialized = FALSE;
70 static gboolean clutter_show_fps = FALSE;
71 static gboolean clutter_fatal_warnings = FALSE;
72 static gboolean clutter_disable_mipmap_text = FALSE;
73 static gboolean clutter_use_fuzzy_picking = FALSE;
75 static guint clutter_default_fps = 60;
77 static PangoDirection clutter_text_direction = PANGO_DIRECTION_LTR;
79 static guint clutter_main_loop_level = 0;
80 static GSList *main_loops = NULL;
82 guint clutter_debug_flags = 0; /* global clutter debug flag */
84 const guint clutter_major_version = CLUTTER_MAJOR_VERSION;
85 const guint clutter_minor_version = CLUTTER_MINOR_VERSION;
86 const guint clutter_micro_version = CLUTTER_MICRO_VERSION;
88 #ifdef CLUTTER_ENABLE_DEBUG
89 static const GDebugKey clutter_debug_keys[] = {
90 { "misc", CLUTTER_DEBUG_MISC },
91 { "actor", CLUTTER_DEBUG_ACTOR },
92 { "texture", CLUTTER_DEBUG_TEXTURE },
93 { "event", CLUTTER_DEBUG_EVENT },
94 { "paint", CLUTTER_DEBUG_PAINT },
95 { "gl", CLUTTER_DEBUG_GL },
96 { "alpha", CLUTTER_DEBUG_ALPHA },
97 { "behaviour", CLUTTER_DEBUG_BEHAVIOUR },
98 { "pango", CLUTTER_DEBUG_PANGO },
99 { "backend", CLUTTER_DEBUG_BACKEND },
100 { "scheduler", CLUTTER_DEBUG_SCHEDULER },
101 { "script", CLUTTER_DEBUG_SCRIPT },
102 { "shader", CLUTTER_DEBUG_SHADER },
103 { "multistage", CLUTTER_DEBUG_MULTISTAGE },
104 { "animation", CLUTTER_DEBUG_ANIMATION },
105 { "layout", CLUTTER_DEBUG_LAYOUT },
106 { "nop-picking", CLUTTER_DEBUG_NOP_PICKING },
107 { "dump-pick-buffers", CLUTTER_DEBUG_DUMP_PICK_BUFFERS }
109 #endif /* CLUTTER_ENABLE_DEBUG */
112 * clutter_get_show_fps:
114 * Returns whether Clutter should print out the frames per second on the
115 * console. You can enable this setting either using the
116 * <literal>CLUTTER_SHOW_FPS</literal> environment variable or passing
117 * the <literal>--clutter-show-fps</literal> command line argument. *
119 * Return value: %TRUE if Clutter should show the FPS.
124 clutter_get_show_fps (void)
126 return clutter_show_fps;
130 _clutter_stage_maybe_relayout (ClutterActor *stage)
132 gfloat natural_width, natural_height;
133 ClutterActorBox box = { 0, };
135 /* avoid reentrancy */
136 if (!(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_RELAYOUT))
138 CLUTTER_NOTE (ACTOR, "Recomputing layout");
140 CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
142 natural_width = natural_height = 0;
143 clutter_actor_get_preferred_size (stage,
145 &natural_width, &natural_height);
149 box.x2 = natural_width;
150 box.y2 = natural_height;
152 CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
154 (int) natural_height);
156 clutter_actor_allocate (stage, &box, CLUTTER_ALLOCATION_NONE);
158 CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
163 _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
165 if ((CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES) &&
166 !(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_STAGE_IN_RESIZE))
168 ClutterPerspective perspective;
169 gfloat width, height;
171 clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage),
174 clutter_stage_get_perspective (stage, &perspective);
177 "Setting up the viewport { w:%.2f, h:%.2f }",
180 _cogl_setup_viewport (width, height,
186 CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
191 _clutter_do_redraw (ClutterStage *stage)
193 ClutterMainContext *ctx;
194 ClutterMasterClock *master_clock;
195 static GTimer *timer = NULL;
196 static guint timer_n_frames = 0;
198 ctx = _clutter_context_get_default ();
199 master_clock = _clutter_master_clock_get_default ();
201 /* Before we can paint, we have to be sure we have the latest layout */
202 _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
204 _clutter_backend_ensure_context (ctx->backend, stage);
206 /* Setup FPS count - not currently across *all* stages rather than per */
207 if (G_UNLIKELY (clutter_get_show_fps ()))
210 timer = g_timer_new ();
213 /* The code below can't go in stage paint as base actor_paint
214 * will get called before it (and break picking, etc)
216 _clutter_stage_maybe_setup_viewport (stage);
218 /* Call through to the actual backend to do the painting down from
219 * the stage. It will likely need to swap buffers, vblank sync etc
220 * which will be windowing system dependent
222 _clutter_backend_redraw (ctx->backend, stage);
224 /* Complete FPS info */
225 if (G_UNLIKELY (clutter_get_show_fps ()))
229 if (g_timer_elapsed (timer, NULL) >= 1.0)
231 g_print ("*** FPS: %i ***\n", timer_n_frames);
233 g_timer_start (timer);
237 CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage);
243 * Forces a redraw of the entire stage. Applications should never use this
244 * function, but queue a redraw using clutter_actor_queue_redraw().
246 * This function should only be used by libraries integrating Clutter from
247 * within another toolkit.
250 clutter_redraw (ClutterStage *stage)
252 g_return_if_fail (CLUTTER_IS_STAGE (stage));
254 clutter_stage_ensure_redraw (stage);
258 * clutter_set_motion_events_enabled:
259 * @enable: %TRUE to enable per-actor motion events
261 * Sets whether per-actor motion events should be enabled or not (the
262 * default is to enable them).
264 * If @enable is %FALSE the following events will not work:
266 * <listitem><para>ClutterActor::motion-event, unless on the
267 * #ClutterStage</para></listitem>
268 * <listitem><para>ClutterActor::enter-event</para></listitem>
269 * <listitem><para>ClutterActor::leave-event</para></listitem>
275 clutter_set_motion_events_enabled (gboolean enable)
277 ClutterMainContext *context = _clutter_context_get_default ();
279 context->motion_events_per_actor = enable;
283 * clutter_get_motion_events_enabled:
285 * Gets whether the per-actor motion events are enabled.
287 * Return value: %TRUE if the motion events are enabled
292 clutter_get_motion_events_enabled (void)
294 ClutterMainContext *context = _clutter_context_get_default ();
296 return context->motion_events_per_actor;
299 guint _clutter_pix_to_id (guchar pixel[4]);
301 static inline void init_bits (void)
303 ClutterMainContext *ctx;
305 static gboolean done = FALSE;
309 ctx = _clutter_context_get_default ();
315 _clutter_id_to_color (guint id, ClutterColor *col)
317 ClutterMainContext *ctx;
318 gint red, green, blue;
320 ctx = _clutter_context_get_default ();
322 /* compute the numbers we'll store in the components */
323 red = (id >> (ctx->fb_g_mask_used+ctx->fb_b_mask_used))
324 & (0xff >> (8-ctx->fb_r_mask_used));
325 green = (id >> ctx->fb_b_mask_used) & (0xff >> (8-ctx->fb_g_mask_used));
326 blue = (id) & (0xff >> (8-ctx->fb_b_mask_used));
328 /* shift left bits a bit and add one, this circumvents
329 * at least some potential rounding errors in GL/GLES
330 * driver / hw implementation.
332 if (ctx->fb_r_mask_used != ctx->fb_r_mask)
334 if (ctx->fb_g_mask_used != ctx->fb_g_mask)
336 if (ctx->fb_b_mask_used != ctx->fb_b_mask)
339 /* shift up to be full 8bit values */
340 red = (red << (8 - ctx->fb_r_mask)) | (0x7f >> (ctx->fb_r_mask_used));
341 green = (green << (8 - ctx->fb_g_mask)) | (0x7f >> (ctx->fb_g_mask_used));
342 blue = (blue << (8 - ctx->fb_b_mask)) | (0x7f >> (ctx->fb_b_mask_used));
349 /* XXX: We rotate the nibbles of the colors here so that there is a
350 * visible variation between colors of sequential actor identifiers;
351 * otherwise pick buffers dumped to an image will pretty much just look
354 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
356 col->red = (col->red << 4) | (col->red >> 4);
357 col->green = (col->green << 4) | (col->green >> 4);
358 col->blue = (col->blue << 4) | (col->blue >> 4);
363 _clutter_pixel_to_id (guchar pixel[4])
365 ClutterMainContext *ctx;
366 gint red, green, blue;
369 ctx = _clutter_context_get_default ();
371 /* reduce the pixel components to the number of bits actually used of the
374 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
378 /* XXX: In _clutter_id_to_color we rotated the nibbles of the colors so
379 * that there is a visible variation between colors of sequential actor
380 * identifiers (otherwise pick buffers dumped to an image will pretty
381 * much just look black.) Here we reverse that rotation.
383 tmp = ((pixel[0] << 4) | (pixel[0] >> 4));
384 red = tmp >> (8 - ctx->fb_r_mask);
385 tmp = ((pixel[1] << 4) | (pixel[1] >> 4));
386 green = tmp >> (8 - ctx->fb_g_mask);
387 tmp = ((pixel[2] << 4) | (pixel[2] >> 4));
388 blue = tmp >> (8 - ctx->fb_b_mask);
392 red = pixel[0] >> (8 - ctx->fb_r_mask);
393 green = pixel[1] >> (8 - ctx->fb_g_mask);
394 blue = pixel[2] >> (8 - ctx->fb_b_mask);
397 /* divide potentially by two if 'fuzzy' */
398 red = red >> (ctx->fb_r_mask - ctx->fb_r_mask_used);
399 green = green >> (ctx->fb_g_mask - ctx->fb_g_mask_used);
400 blue = blue >> (ctx->fb_b_mask - ctx->fb_b_mask_used);
402 /* combine the correct per component values into the final id */
403 id = blue + (green << ctx->fb_b_mask_used)
404 + (red << (ctx->fb_b_mask_used + ctx->fb_g_mask_used));
411 pixbuf_free (guchar *pixels, gpointer data)
418 read_pixels_to_file (char *filename_stem,
427 static int read_count = 0;
429 data = g_malloc (4 * width * height);
430 cogl_read_pixels (x, y, width, height,
431 COGL_READ_PIXELS_COLOR_BUFFER,
432 COGL_PIXEL_FORMAT_RGBA_8888,
434 pixbuf = gdk_pixbuf_new_from_data (data,
436 TRUE, /* has alpha */
437 8, /* bits per sample */
440 width * 4, /* rowstride */
441 pixbuf_free, /* callback to free data */
442 NULL); /* callback data */
446 g_strdup_printf ("%s-%05d.png", filename_stem, read_count);
447 GError *error = NULL;
448 if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL))
450 g_warning ("Failed to save pick buffer to file %s: %s",
451 filename, error->message);
452 g_error_free (error);
455 g_object_unref (pixbuf);
459 static gboolean seen = FALSE;
462 g_warning ("dumping buffers to an image isn't supported on platforms "
463 "without gdk pixbuf support\n");
470 _clutter_do_pick (ClutterStage *stage,
473 ClutterPickMode mode)
475 ClutterMainContext *context;
476 guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
479 GLboolean dither_was_on;
481 if (clutter_debug_flags & CLUTTER_DEBUG_NOP_PICKING)
482 return CLUTTER_ACTOR (stage);
484 context = _clutter_context_get_default ();
486 _clutter_backend_ensure_context (context->backend, stage);
488 /* needed for when a context switch happens */
489 _clutter_stage_maybe_setup_viewport (stage);
491 if (G_LIKELY (!(clutter_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
492 cogl_clip_push_window_rectangle (x, y, 1, 1);
494 cogl_color_set_from_4ub (&white, 255, 255, 255, 255);
497 COGL_BUFFER_BIT_COLOR |
498 COGL_BUFFER_BIT_DEPTH);
500 /* Disable dithering (if any) when doing the painting in pick mode */
501 dither_was_on = glIsEnabled (GL_DITHER);
503 glDisable (GL_DITHER);
505 /* Render the entire scence in pick mode - just single colored silhouette's
506 * are drawn offscreen (as we never swap buffers)
508 context->pick_mode = mode;
509 clutter_actor_paint (CLUTTER_ACTOR (stage));
510 context->pick_mode = CLUTTER_PICK_NONE;
512 if (G_LIKELY (!(clutter_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
515 /* Make sure Cogl flushes any batched geometry to the GPU driver */
518 /* Read the color of the screen co-ords pixel */
519 cogl_read_pixels (x, y, 1, 1,
520 COGL_READ_PIXELS_COLOR_BUFFER,
521 COGL_PIXEL_FORMAT_RGBA_8888,
524 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
526 read_pixels_to_file ("pick-buffer", 0, 0,
527 clutter_actor_get_width (CLUTTER_ACTOR (stage)),
528 clutter_actor_get_height (CLUTTER_ACTOR (stage)));
531 /* Restore whether GL_DITHER was enabled */
533 glEnable (GL_DITHER);
535 if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
536 return CLUTTER_ACTOR (stage);
538 id = _clutter_pixel_to_id (pixel);
540 return clutter_get_actor_by_gid (id);
543 static PangoDirection
544 clutter_get_text_direction (void)
546 PangoDirection dir = PANGO_DIRECTION_LTR;
547 const gchar *direction;
549 direction = g_getenv ("CLUTTER_TEXT_DIRECTION");
550 if (direction && *direction != '\0')
552 if (strcmp (direction, "rtl") == 0)
553 dir = PANGO_DIRECTION_RTL;
554 else if (strcmp (direction, "ltr") == 0)
555 dir = PANGO_DIRECTION_LTR;
559 /* Translate to default:RTL if you want your widgets
560 * to be RTL, otherwise translate to default:LTR.
562 * Do *not* translate it to "predefinito:LTR": if it
563 * it isn't default:LTR or default:RTL it will not work
565 char *e = _("default:LTR");
567 if (strcmp (e, "default:RTL") == 0)
568 dir = PANGO_DIRECTION_RTL;
569 else if (strcmp (e, "default:LTR") == 0)
570 dir = PANGO_DIRECTION_LTR;
572 g_warning ("Whoever translated default:LTR did so wrongly.");
579 update_pango_context (ClutterBackend *backend,
580 PangoContext *context)
582 PangoFontDescription *font_desc;
583 const cairo_font_options_t *font_options;
584 const gchar *font_name;
587 /* update the text direction */
588 pango_context_set_base_dir (context, clutter_text_direction);
590 /* get the configuration for the PangoContext from the backend */
591 font_name = clutter_backend_get_font_name (backend);
592 font_options = clutter_backend_get_font_options (backend);
593 resolution = clutter_backend_get_resolution (backend);
595 font_desc = pango_font_description_from_string (font_name);
598 resolution = 96.0; /* fall back */
600 pango_context_set_font_description (context, font_desc);
601 pango_cairo_context_set_font_options (context, font_options);
602 pango_cairo_context_set_resolution (context, resolution);
604 pango_font_description_free (font_desc);
608 _clutter_context_get_pango_context (ClutterMainContext *self)
610 if (G_UNLIKELY (self->pango_context == NULL))
612 PangoContext *context;
614 context = cogl_pango_font_map_create_context (self->font_map);
615 self->pango_context = context;
617 g_signal_connect (self->backend, "resolution-changed",
618 G_CALLBACK (update_pango_context),
619 self->pango_context);
620 g_signal_connect (self->backend, "font-changed",
621 G_CALLBACK (update_pango_context),
622 self->pango_context);
625 update_pango_context (self->backend, self->pango_context);
627 return self->pango_context;
631 _clutter_context_create_pango_context (ClutterMainContext *self)
633 PangoContext *context;
635 context = cogl_pango_font_map_create_context (self->font_map);
636 update_pango_context (self->backend, context);
644 * Terminates the Clutter mainloop.
647 clutter_main_quit (void)
649 g_return_if_fail (main_loops != NULL);
651 g_main_loop_quit (main_loops->data);
655 * clutter_main_level:
657 * Retrieves the depth of the Clutter mainloop.
659 * Return value: The level of the mainloop.
662 clutter_main_level (void)
664 return clutter_main_loop_level;
670 * Starts the Clutter mainloop.
677 /* Make sure there is a context */
680 if (!clutter_is_initialized)
682 g_warning ("Called clutter_main() but Clutter wasn't initialised. "
683 "You must call clutter_init() first.");
689 clutter_main_loop_level++;
691 loop = g_main_loop_new (NULL, TRUE);
692 main_loops = g_slist_prepend (main_loops, loop);
694 #ifdef HAVE_CLUTTER_FRUITY
695 /* clutter fruity creates an application that forwards events and manually
698 clutter_fruity_main ();
700 if (g_main_loop_is_running (main_loops->data))
702 clutter_threads_leave ();
703 g_main_loop_run (loop);
704 clutter_threads_enter ();
708 main_loops = g_slist_remove (main_loops, loop);
710 g_main_loop_unref (loop);
712 clutter_main_loop_level--;
718 clutter_threads_impl_lock (void)
720 if (clutter_threads_mutex)
721 g_mutex_lock (clutter_threads_mutex);
725 clutter_threads_impl_unlock (void)
727 if (clutter_threads_mutex)
728 g_mutex_unlock (clutter_threads_mutex);
732 * clutter_threads_init:
734 * Initialises the Clutter threading mechanism, so that Clutter API can be
735 * called by multiple threads, using clutter_threads_enter() and
736 * clutter_threads_leave() to mark the critical sections.
738 * You must call g_thread_init() before this function.
740 * This function must be called before clutter_init().
745 clutter_threads_init (void)
747 if (!g_thread_supported ())
748 g_error ("g_thread_init() must be called before clutter_threads_init()");
750 clutter_threads_mutex = g_mutex_new ();
752 if (!clutter_threads_lock)
753 clutter_threads_lock = clutter_threads_impl_lock;
755 if (!clutter_threads_unlock)
756 clutter_threads_unlock = clutter_threads_impl_unlock;
760 * clutter_threads_set_lock_functions:
761 * @enter_fn: function called when aquiring the Clutter main lock
762 * @leave_fn: function called when releasing the Clutter main lock
764 * Allows the application to replace the standard method that
765 * Clutter uses to protect its data structures. Normally, Clutter
766 * creates a single #GMutex that is locked by clutter_threads_enter(),
767 * and released by clutter_threads_leave(); using this function an
768 * application provides, instead, a function @enter_fn that is
769 * called by clutter_threads_enter() and a function @leave_fn that is
770 * called by clutter_threads_leave().
772 * The functions must provide at least same locking functionality
773 * as the default implementation, but can also do extra application
774 * specific processing.
776 * As an example, consider an application that has its own recursive
777 * lock that when held, holds the Clutter lock as well. When Clutter
778 * unlocks the Clutter lock when entering a recursive main loop, the
779 * application must temporarily release its lock as well.
781 * Most threaded Clutter apps won't need to use this method.
783 * This method must be called before clutter_threads_init(), and cannot
784 * be called multiple times.
789 clutter_threads_set_lock_functions (GCallback enter_fn,
792 g_return_if_fail (clutter_threads_lock == NULL &&
793 clutter_threads_unlock == NULL);
795 clutter_threads_lock = enter_fn;
796 clutter_threads_unlock = leave_fn;
803 GDestroyNotify notify;
804 } ClutterThreadsDispatch;
807 clutter_threads_dispatch (gpointer data)
809 ClutterThreadsDispatch *dispatch = data;
810 gboolean ret = FALSE;
812 clutter_threads_enter ();
814 if (!g_source_is_destroyed (g_main_current_source ()))
815 ret = dispatch->func (dispatch->data);
817 clutter_threads_leave ();
823 clutter_threads_dispatch_free (gpointer data)
825 ClutterThreadsDispatch *dispatch = data;
827 /* XXX - we cannot hold the thread lock here because the main loop
828 * might destroy a source while still in the dispatcher function; so
829 * knowing whether the lock is being held or not is not known a priori.
831 * see bug: http://bugzilla.gnome.org/show_bug.cgi?id=459555
833 if (dispatch->notify)
834 dispatch->notify (dispatch->data);
836 g_slice_free (ClutterThreadsDispatch, dispatch);
840 * clutter_threads_add_idle_full:
841 * @priority: the priority of the timeout source. Typically this will be in the
842 * range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
843 * @func: function to call
844 * @data: data to pass to the function
845 * @notify: functio to call when the idle source is removed
847 * Adds a function to be called whenever there are no higher priority
848 * events pending. If the function returns %FALSE it is automatically
849 * removed from the list of event sources and will not be called again.
851 * This function can be considered a thread-safe variant of g_idle_add_full():
852 * it will call @function while holding the Clutter lock. It is logically
853 * equivalent to the following implementation:
857 * idle_safe_callback (gpointer data)
859 * SafeClosure *closure = data;
860 * gboolean res = FALSE;
862 * /* mark the critical section */
864 * clutter_threads_enter();
866 * /* the callback does not need to acquire the Clutter
867 * * lock itself, as it is held by the this proxy handler
869 * res = closure->callback (closure->data);
871 * clutter_threads_leave();
876 * add_safe_idle (GSourceFunc callback,
879 * SafeClosure *closure = g_new0 (SafeClosure, 1);
881 * closure->callback = callback;
882 * closure->data = data;
884 * return g_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
885 * idle_safe_callback,
891 * This function should be used by threaded applications to make sure
892 * that @func is emitted under the Clutter threads lock and invoked
893 * from the same thread that started the Clutter main loop. For instance,
894 * it can be used to update the UI using the results from a worker
899 * update_ui (gpointer data)
901 * SomeClosure *closure = data;
903 * /* it is safe to call Clutter API from this function because
904 * * it is invoked from the same thread that started the main
905 * * loop and under the Clutter thread lock
907 * clutter_label_set_text (CLUTTER_LABEL (closure->label),
910 * g_object_unref (closure->label);
916 * /* within another thread */
917 * closure = g_new0 (SomeClosure, 1);
918 * /* always take a reference on GObject instances */
919 * closure->label = g_object_ref (my_application->label);
920 * closure->text = g_strdup (processed_text_to_update_the_label);
922 * clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE,
928 * Return value: the ID (greater than 0) of the event source.
933 clutter_threads_add_idle_full (gint priority,
936 GDestroyNotify notify)
938 ClutterThreadsDispatch *dispatch;
940 g_return_val_if_fail (func != NULL, 0);
942 dispatch = g_slice_new (ClutterThreadsDispatch);
943 dispatch->func = func;
944 dispatch->data = data;
945 dispatch->notify = notify;
947 return g_idle_add_full (priority,
948 clutter_threads_dispatch, dispatch,
949 clutter_threads_dispatch_free);
953 * clutter_threads_add_idle:
954 * @func: function to call
955 * @data: data to pass to the function
957 * Simple wrapper around clutter_threads_add_idle_full() using the
960 * Return value: the ID (greater than 0) of the event source.
965 clutter_threads_add_idle (GSourceFunc func,
968 g_return_val_if_fail (func != NULL, 0);
970 return clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
976 * clutter_threads_add_timeout_full:
977 * @priority: the priority of the timeout source. Typically this will be in the
978 * range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
979 * @interval: the time between calls to the function, in milliseconds
980 * @func: function to call
981 * @data: data to pass to the function
982 * @notify: function to call when the timeout source is removed
984 * Sets a function to be called at regular intervals holding the Clutter
985 * threads lock, with the given priority. The function is called repeatedly
986 * until it returns %FALSE, at which point the timeout is automatically
987 * removed and the function will not be called again. The @notify function
988 * is called when the timeout is removed.
990 * The first call to the function will be at the end of the first @interval.
992 * It is important to note that, due to how the Clutter main loop is
993 * implemented, the timing will not be accurate and it will not try to
994 * "keep up" with the interval. A more reliable source is available
995 * using clutter_threads_add_frame_source_full(), which is also internally
996 * used by #ClutterTimeline.
998 * See also clutter_threads_add_idle_full().
1000 * Return value: the ID (greater than 0) of the event source.
1005 clutter_threads_add_timeout_full (gint priority,
1009 GDestroyNotify notify)
1011 ClutterThreadsDispatch *dispatch;
1013 g_return_val_if_fail (func != NULL, 0);
1015 dispatch = g_slice_new (ClutterThreadsDispatch);
1016 dispatch->func = func;
1017 dispatch->data = data;
1018 dispatch->notify = notify;
1020 return g_timeout_add_full (priority,
1022 clutter_threads_dispatch, dispatch,
1023 clutter_threads_dispatch_free);
1027 * clutter_threads_add_timeout:
1028 * @interval: the time between calls to the function, in milliseconds
1029 * @func: function to call
1030 * @data: data to pass to the function
1032 * Simple wrapper around clutter_threads_add_timeout_full().
1034 * Return value: the ID (greater than 0) of the event source.
1039 clutter_threads_add_timeout (guint interval,
1043 g_return_val_if_fail (func != NULL, 0);
1045 return clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT,
1052 * clutter_threads_add_frame_source_full:
1053 * @priority: the priority of the frame source. Typically this will be in the
1054 * range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
1055 * @fps: the number of times per second to call the function
1056 * @func: function to call
1057 * @data: data to pass to the function
1058 * @notify: function to call when the timeout source is removed
1060 * Sets a function to be called at regular intervals holding the Clutter
1061 * threads lock, with the given priority. The function is called repeatedly
1062 * until it returns %FALSE, at which point the timeout is automatically
1063 * removed and the function will not be called again. The @notify function
1064 * is called when the timeout is removed.
1066 * This function is similar to clutter_threads_add_timeout_full()
1067 * except that it will try to compensate for delays. For example, if
1068 * @func takes half the interval time to execute then the function
1069 * will be called again half the interval time after it finished. In
1070 * contrast clutter_threads_add_timeout_full() would not fire until a
1071 * full interval after the function completes so the delay between
1072 * calls would be @interval * 1.5. This function does not however try
1073 * to invoke the function multiple times to catch up missing frames if
1074 * @func takes more than @interval ms to execute.
1076 * See also clutter_threads_add_idle_full().
1078 * Return value: the ID (greater than 0) of the event source.
1083 clutter_threads_add_frame_source_full (gint priority,
1087 GDestroyNotify notify)
1089 ClutterThreadsDispatch *dispatch;
1091 g_return_val_if_fail (func != NULL, 0);
1093 dispatch = g_slice_new (ClutterThreadsDispatch);
1094 dispatch->func = func;
1095 dispatch->data = data;
1096 dispatch->notify = notify;
1098 return clutter_frame_source_add_full (priority,
1100 clutter_threads_dispatch, dispatch,
1101 clutter_threads_dispatch_free);
1105 * clutter_threads_add_frame_source:
1106 * @fps: the number of times per second to call the function
1107 * @func: function to call
1108 * @data: data to pass to the function
1110 * Simple wrapper around clutter_threads_add_frame_source_full().
1112 * Return value: the ID (greater than 0) of the event source.
1117 clutter_threads_add_frame_source (guint fps,
1121 g_return_val_if_fail (func != NULL, 0);
1123 return clutter_threads_add_frame_source_full (G_PRIORITY_DEFAULT,
1130 * clutter_threads_enter:
1132 * Locks the Clutter thread lock.
1137 clutter_threads_enter (void)
1139 if (clutter_threads_lock)
1140 (* clutter_threads_lock) ();
1144 * clutter_threads_leave:
1146 * Unlocks the Clutter thread lock.
1151 clutter_threads_leave (void)
1153 if (clutter_threads_unlock)
1154 (* clutter_threads_unlock) ();
1159 * clutter_get_debug_enabled:
1161 * Check if clutter has debugging turned on.
1163 * Return value: TRUE if debugging is turned on, FALSE otherwise.
1166 clutter_get_debug_enabled (void)
1168 #ifdef CLUTTER_ENABLE_DEBUG
1169 return clutter_debug_flags != 0;
1176 _clutter_context_is_initialized (void)
1178 if (ClutterCntx == NULL)
1181 return ClutterCntx->is_initialized;
1184 ClutterMainContext *
1185 _clutter_context_get_default (void)
1187 if (G_UNLIKELY (ClutterCntx == NULL))
1189 ClutterMainContext *ctx;
1191 ClutterCntx = ctx = g_new0 (ClutterMainContext, 1);
1193 ctx->backend = g_object_new (_clutter_backend_impl_get_type (), NULL);
1195 ctx->is_initialized = FALSE;
1196 ctx->motion_events_per_actor = TRUE;
1198 #ifdef CLUTTER_ENABLE_DEBUG
1199 ctx->timer = g_timer_new ();
1200 g_timer_start (ctx->timer);
1208 * clutter_get_timestamp:
1210 * Returns the approximate number of microseconds passed since clutter was
1213 * Return value: Number of microseconds since clutter_init() was called.
1216 clutter_get_timestamp (void)
1218 #ifdef CLUTTER_ENABLE_DEBUG
1219 ClutterMainContext *ctx;
1222 ctx = _clutter_context_get_default ();
1224 /* FIXME: may need a custom timer for embedded setups */
1225 seconds = g_timer_elapsed (ctx->timer, NULL);
1227 return (gulong)(seconds / 1.0e-6);
1234 clutter_arg_direction_cb (const char *key,
1238 clutter_text_direction =
1239 (strcmp (value, "rtl") == 0) ? PANGO_DIRECTION_RTL
1240 : PANGO_DIRECTION_LTR;
1245 #ifdef CLUTTER_ENABLE_DEBUG
1247 clutter_arg_debug_cb (const char *key,
1251 clutter_debug_flags |=
1252 g_parse_debug_string (value,
1254 G_N_ELEMENTS (clutter_debug_keys));
1259 clutter_arg_no_debug_cb (const char *key,
1263 clutter_debug_flags &=
1264 ~g_parse_debug_string (value,
1266 G_N_ELEMENTS (clutter_debug_keys));
1269 #endif /* CLUTTER_ENABLE_DEBUG */
1272 clutter_init_error_quark (void)
1274 return g_quark_from_static_string ("clutter-init-error-quark");
1277 static ClutterInitError
1278 clutter_init_real (GError **error)
1280 ClutterMainContext *ctx;
1281 ClutterActor *stage;
1283 ClutterBackend *backend;
1285 /* Note, creates backend if not already existing, though parse args will
1286 * have likely created it
1288 ctx = _clutter_context_get_default ();
1289 backend = ctx->backend;
1291 if (!ctx->options_parsed)
1293 g_set_error (error, CLUTTER_INIT_ERROR,
1294 CLUTTER_INIT_ERROR_INTERNAL,
1295 "When using clutter_get_option_group_without_init() "
1296 "you must parse options before calling clutter_init()");
1298 return CLUTTER_INIT_ERROR_INTERNAL;
1302 * Call backend post parse hooks.
1304 if (!_clutter_backend_post_parse (backend, error))
1305 return CLUTTER_INIT_ERROR_BACKEND;
1307 /* Stage will give us a GL Context etc */
1308 stage = clutter_stage_get_default ();
1312 g_set_error (error, CLUTTER_INIT_ERROR,
1313 CLUTTER_INIT_ERROR_INTERNAL,
1314 "Unable to create the default stage");
1316 g_critical ("Unable to create the default stage");
1318 return CLUTTER_INIT_ERROR_INTERNAL;
1321 clutter_stage_set_title (CLUTTER_STAGE (stage), g_get_prgname ());
1323 clutter_actor_realize (stage);
1325 if (!CLUTTER_ACTOR_IS_REALIZED (stage))
1328 g_set_error (error, CLUTTER_INIT_ERROR,
1329 CLUTTER_INIT_ERROR_INTERNAL,
1330 "Unable to realize the default stage");
1332 g_critical ("Unable to realize the default stage");
1334 return CLUTTER_INIT_ERROR_INTERNAL;
1337 /* Now we can safely assume we have a valid GL context and can
1338 * start issueing cogl commands
1340 /* - will call to backend and cogl */
1341 _clutter_feature_init ();
1344 * Resolution requires display to be open, so can only be queried after
1345 * the post_parse hooks run.
1347 * NB: cogl_pango requires a Cogl context.
1349 ctx->font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new ());
1351 resolution = clutter_backend_get_resolution (ctx->backend);
1352 cogl_pango_font_map_set_resolution (ctx->font_map, resolution);
1354 if (G_LIKELY (!clutter_disable_mipmap_text))
1355 cogl_pango_font_map_set_use_mipmapping (ctx->font_map, TRUE);
1357 clutter_text_direction = clutter_get_text_direction ();
1360 /* Figure out framebuffer masks used for pick */
1361 cogl_get_bitmasks (&ctx->fb_r_mask, &ctx->fb_g_mask, &ctx->fb_b_mask, NULL);
1363 ctx->fb_r_mask_used = ctx->fb_r_mask;
1364 ctx->fb_g_mask_used = ctx->fb_g_mask;
1365 ctx->fb_b_mask_used = ctx->fb_b_mask;
1367 /* XXX - describe what "fuzzy picking" is */
1368 if (clutter_use_fuzzy_picking)
1370 ctx->fb_r_mask_used--;
1371 ctx->fb_g_mask_used--;
1372 ctx->fb_b_mask_used--;
1375 /* Initiate event collection */
1376 _clutter_backend_init_events (ctx->backend);
1378 clutter_is_initialized = TRUE;
1379 ctx->is_initialized = TRUE;
1381 return CLUTTER_INIT_SUCCESS;
1384 static GOptionEntry clutter_args[] = {
1385 { "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
1386 N_("Show frames per second"), NULL },
1387 { "clutter-default-fps", 0, 0, G_OPTION_ARG_INT, &clutter_default_fps,
1388 N_("Default frame rate"), "FPS" },
1389 { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings,
1390 N_("Make all warnings fatal"), NULL },
1391 { "clutter-text-direction", 0, 0, G_OPTION_ARG_CALLBACK,
1392 clutter_arg_direction_cb,
1393 N_("Direction for the text"), "DIRECTION" },
1394 { "clutter-disable-mipmapped-text", 0, 0, G_OPTION_ARG_NONE,
1395 &clutter_disable_mipmap_text,
1396 N_("Disable mipmapping on text"), NULL },
1397 { "clutter-use-fuzzy-picking", 0, 0, G_OPTION_ARG_NONE,
1398 &clutter_use_fuzzy_picking,
1399 N_("Use 'fuzzy' picking"), NULL },
1400 #ifdef CLUTTER_ENABLE_DEBUG
1401 { "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
1402 N_("Clutter debugging flags to set"), "FLAGS" },
1403 { "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb,
1404 N_("Clutter debugging flags to unset"), "FLAGS" },
1405 #endif /* CLUTTER_ENABLE_DEBUG */
1409 /* pre_parse_hook: initialise variables depending on environment
1410 * variables; these variables might be overridden by the command
1411 * line arguments that are going to be parsed after.
1414 pre_parse_hook (GOptionContext *context,
1415 GOptionGroup *group,
1419 ClutterMainContext *clutter_context;
1420 ClutterBackend *backend;
1421 const char *env_string;
1423 if (clutter_is_initialized)
1426 if (setlocale (LC_ALL, "") == NULL)
1427 g_warning ("Locale not supported by C library.\n"
1428 "Using the fallback 'C' locale.");
1430 clutter_context = _clutter_context_get_default ();
1432 clutter_context->id_pool = clutter_id_pool_new (256);
1434 backend = clutter_context->backend;
1435 g_assert (CLUTTER_IS_BACKEND (backend));
1437 #ifdef CLUTTER_ENABLE_DEBUG
1438 env_string = g_getenv ("CLUTTER_DEBUG");
1439 if (env_string != NULL)
1441 clutter_debug_flags =
1442 g_parse_debug_string (env_string,
1444 G_N_ELEMENTS (clutter_debug_keys));
1447 #endif /* CLUTTER_ENABLE_DEBUG */
1449 env_string = g_getenv ("CLUTTER_SHOW_FPS");
1451 clutter_show_fps = TRUE;
1453 env_string = g_getenv ("CLUTTER_DEFAULT_FPS");
1456 gint default_fps = g_ascii_strtoll (env_string, NULL, 10);
1458 clutter_default_fps = CLAMP (default_fps, 1, 1000);
1461 env_string = g_getenv ("CLUTTER_DISABLE_MIPMAPPED_TEXT");
1463 clutter_disable_mipmap_text = TRUE;
1465 #ifdef HAVE_CLUTTER_FRUITY
1466 /* we always enable fuzzy picking in the "fruity" backend */
1467 clutter_use_fuzzy_picking = TRUE;
1469 env_string = g_getenv ("CLUTTER_FUZZY_PICK");
1471 clutter_use_fuzzy_picking = TRUE;
1472 #endif /* HAVE_CLUTTER_FRUITY */
1474 return _clutter_backend_pre_parse (backend, error);
1477 /* post_parse_hook: initialise the context and data structures
1478 * and opens the X display
1481 post_parse_hook (GOptionContext *context,
1482 GOptionGroup *group,
1486 ClutterMainContext *clutter_context;
1487 ClutterBackend *backend;
1489 if (clutter_is_initialized)
1492 clutter_context = _clutter_context_get_default ();
1493 backend = clutter_context->backend;
1494 g_assert (CLUTTER_IS_BACKEND (backend));
1496 if (clutter_fatal_warnings)
1498 GLogLevelFlags fatal_mask;
1500 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
1501 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
1502 g_log_set_always_fatal (fatal_mask);
1505 clutter_context->frame_rate = clutter_default_fps;
1506 clutter_context->options_parsed = TRUE;
1509 * If not asked to defer display setup, call clutter_init_real(),
1510 * which in turn calls the backend post parse hooks.
1512 if (!clutter_context->defer_display_setup)
1513 return clutter_init_real (error);
1519 * clutter_get_option_group:
1521 * Returns a #GOptionGroup for the command line arguments recognized
1522 * by Clutter. You should add this group to your #GOptionContext with
1523 * g_option_context_add_group(), if you are using g_option_context_parse()
1524 * to parse your commandline arguments.
1526 * Calling g_option_context_parse() with Clutter's #GOptionGroup will result
1527 * in Clutter's initialization. That is, the following code:
1530 * g_option_context_set_main_group (context, clutter_get_option_group ());
1531 * res = g_option_context_parse (context, &argc, &argc, NULL);
1534 * is functionally equivalent to:
1537 * clutter_init (&argc, &argv);
1540 * After g_option_context_parse() on a #GOptionContext containing the
1541 * Clutter #GOptionGroup has returned %TRUE, Clutter is guaranteed to be
1544 * Return value: (transfer full): a #GOptionGroup for the commandline arguments
1545 * recognized by Clutter
1550 clutter_get_option_group (void)
1552 ClutterMainContext *context;
1553 GOptionGroup *group;
1555 clutter_base_init ();
1557 context = _clutter_context_get_default ();
1559 group = g_option_group_new ("clutter",
1560 _("Clutter Options"),
1561 _("Show Clutter Options"),
1565 g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
1566 g_option_group_add_entries (group, clutter_args);
1567 g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
1569 /* add backend-specific options */
1570 _clutter_backend_add_options (context->backend, group);
1576 * clutter_get_option_group_without_init:
1578 * Returns a #GOptionGroup for the command line arguments recognized
1579 * by Clutter. You should add this group to your #GOptionContext with
1580 * g_option_context_add_group(), if you are using g_option_context_parse()
1581 * to parse your commandline arguments. Unlike clutter_get_option_group(),
1582 * calling g_option_context_parse() with the #GOptionGroup returned by this
1583 * function requires a subsequent explicit call to clutter_init(); use this
1584 * function when needing to set foreign display connection with
1585 * clutter_x11_set_display(), or with gtk_clutter_init().
1587 * Return value: (transfer full): a #GOptionGroup for the commandline arguments
1588 * recognized by Clutter
1593 clutter_get_option_group_without_init (void)
1595 ClutterMainContext *context;
1596 GOptionGroup *group;
1598 clutter_base_init ();
1600 context = _clutter_context_get_default ();
1601 context->defer_display_setup = TRUE;
1603 group = clutter_get_option_group ();
1608 /* Note that the gobject-introspection annotations for the argc/argv
1609 * parameters do not produce the right result; however, they do
1610 * allow the common case of argc=NULL, argv=NULL to work.
1614 * clutter_init_with_args:
1615 * @argc: (inout): a pointer to the number of command line arguments
1616 * @argv: (array length=argc) (inout) (allow-none): a pointer to the array
1617 * of command line arguments
1618 * @parameter_string: (allow-none): a string which is displayed in the
1619 * first line of <option>--help</option> output, after
1620 * <literal><replaceable>programname</replaceable> [OPTION...]</literal>
1621 * @entries: (allow-none): a %NULL terminated array of #GOptionEntry<!-- -->s
1622 * describing the options of your program
1623 * @translation_domain: (allow-none): a translation domain to use for
1624 * translating the <option>--help</option> output for the options in
1625 * @entries with gettext(), or %NULL
1626 * @error: (allow-none): a return location for a #GError
1628 * This function does the same work as clutter_init(). Additionally,
1629 * it allows you to add your own command line options, and it
1630 * automatically generates nicely formatted <option>--help</option>
1631 * output. Note that your program will be terminated after writing
1632 * out the help output. Also note that, in case of error, the
1633 * error message will be placed inside @error instead of being
1634 * printed on the display.
1636 * Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully
1637 * initialised, or other values or #ClutterInitError in case of
1643 clutter_init_with_args (int *argc,
1645 const char *parameter_string,
1646 GOptionEntry *entries,
1647 const char *translation_domain,
1650 GOptionContext *context;
1651 GOptionGroup *group;
1653 ClutterMainContext *ctx;
1655 if (clutter_is_initialized)
1656 return CLUTTER_INIT_SUCCESS;
1658 clutter_base_init ();
1660 ctx = _clutter_context_get_default ();
1662 if (!ctx->defer_display_setup)
1664 if (argc && *argc > 0 && *argv)
1665 g_set_prgname ((*argv)[0]);
1667 context = g_option_context_new (parameter_string);
1669 group = clutter_get_option_group ();
1670 g_option_context_add_group (context, group);
1672 group = cogl_get_option_group ();
1673 g_option_context_add_group (context, group);
1676 g_option_context_add_main_entries (context, entries, translation_domain);
1678 res = g_option_context_parse (context, argc, argv, error);
1679 g_option_context_free (context);
1681 /* if res is FALSE, the error is filled for
1682 * us by g_option_context_parse()
1686 /* if there has been an error in the initialization, the
1687 * error id will be preserved inside the GError code
1689 if (error && *error)
1690 return (*error)->code;
1692 return CLUTTER_INIT_ERROR_INTERNAL;
1695 return CLUTTER_INIT_SUCCESS;
1698 return clutter_init_real (error);
1702 clutter_parse_args (int *argc,
1705 GOptionContext *option_context;
1706 GOptionGroup *clutter_group, *cogl_group;
1707 GError *error = NULL;
1708 gboolean ret = TRUE;
1710 if (clutter_is_initialized)
1713 option_context = g_option_context_new (NULL);
1714 g_option_context_set_ignore_unknown_options (option_context, TRUE);
1715 g_option_context_set_help_enabled (option_context, FALSE);
1717 /* Initiate any command line options from the backend */
1719 clutter_group = clutter_get_option_group ();
1720 g_option_context_set_main_group (option_context, clutter_group);
1722 cogl_group = cogl_get_option_group ();
1723 g_option_context_add_group (option_context, cogl_group);
1725 if (!g_option_context_parse (option_context, argc, argv, &error))
1729 g_warning ("%s", error->message);
1730 g_error_free (error);
1736 g_option_context_free (option_context);
1743 * @argc: (inout): The number of arguments in @argv
1744 * @argv: (array length=argc) (inout) (allow-none): A pointer to an array
1747 * It will initialise everything needed to operate with Clutter and
1748 * parses some standard command line options. @argc and @argv are
1749 * adjusted accordingly so your own code will never see those standard
1752 * Return value: 1 on success, < 0 on failure.
1755 clutter_init (int *argc,
1758 ClutterMainContext *ctx;
1759 GError *error = NULL;
1761 if (clutter_is_initialized)
1762 return CLUTTER_INIT_SUCCESS;
1764 clutter_base_init ();
1766 ctx = _clutter_context_get_default ();
1768 if (!ctx->defer_display_setup)
1770 if (argc && *argc > 0 && *argv)
1771 g_set_prgname ((*argv)[0]);
1773 /* parse_args will trigger backend creation and things like
1774 * DISPLAY connection etc.
1776 if (clutter_parse_args (argc, argv) == FALSE)
1778 CLUTTER_NOTE (MISC, "failed to parse arguments.");
1779 return CLUTTER_INIT_ERROR_INTERNAL;
1782 return CLUTTER_INIT_SUCCESS;
1785 return clutter_init_real (&error);
1789 _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
1790 GValue *return_accu,
1791 const GValue *handler_return,
1794 gboolean continue_emission;
1795 gboolean signal_handled;
1797 signal_handled = g_value_get_boolean (handler_return);
1798 g_value_set_boolean (return_accu, signal_handled);
1799 continue_emission = !signal_handled;
1801 return continue_emission;
1805 event_click_count_generate (ClutterEvent *event)
1807 /* multiple button click detection */
1808 static gint click_count = 0;
1809 static gint previous_x = -1;
1810 static gint previous_y = -1;
1811 static guint32 previous_time = 0;
1812 static gint previous_button_number = -1;
1814 ClutterBackend *backend;
1815 guint double_click_time;
1816 guint double_click_distance;
1818 backend = _clutter_context_get_default ()->backend;
1819 double_click_distance = clutter_backend_get_double_click_distance (backend);
1820 double_click_time = clutter_backend_get_double_click_time (backend);
1822 if (event->button.device != NULL)
1824 click_count = event->button.device->click_count;
1825 previous_x = event->button.device->previous_x;
1826 previous_y = event->button.device->previous_y;
1827 previous_time = event->button.device->previous_time;
1828 previous_button_number = event->button.device->previous_button_number;
1831 switch (event->type)
1833 case CLUTTER_BUTTON_PRESS:
1834 case CLUTTER_SCROLL:
1835 /* check if we are in time and within distance to increment an
1836 * existing click count
1838 if (event->button.time < previous_time + double_click_time &&
1839 (ABS (event->button.x - previous_x) <= double_click_distance) &&
1840 (ABS (event->button.y - previous_y) <= double_click_distance)
1841 && event->button.button == previous_button_number)
1845 else /* start a new click count*/
1848 previous_button_number = event->button.button;
1851 /* store time and position for this click for comparison with
1854 previous_time = event->button.time;
1855 previous_x = event->button.x;
1856 previous_y = event->button.y;
1859 case CLUTTER_BUTTON_RELEASE:
1860 event->button.click_count=click_count;
1866 if (event->button.device != NULL)
1868 event->button.device->click_count = click_count;
1869 event->button.device->previous_x = previous_x;
1870 event->button.device->previous_y = previous_y;
1871 event->button.device->previous_time = previous_time;
1872 event->button.device->previous_button_number = previous_button_number;
1878 emit_event (ClutterEvent *event,
1879 gboolean is_key_event)
1881 static gboolean lock = FALSE;
1883 GPtrArray *event_tree = NULL;
1884 ClutterActor *actor;
1887 if (!event->any.source)
1889 CLUTTER_NOTE (EVENT, "No source set, discarding event");
1893 /* reentrancy check */
1896 g_warning ("Tried emitting event during event delivery, bailing out.n");
1902 event_tree = g_ptr_array_sized_new (64);
1904 actor = event->any.source;
1906 /* Build 'tree' of emitters for the event */
1909 ClutterActor *parent;
1911 parent = clutter_actor_get_parent (actor);
1913 if (clutter_actor_get_reactive (actor) ||
1914 parent == NULL || /* stage gets all events */
1915 is_key_event) /* keyboard events are always emitted */
1917 g_ptr_array_add (event_tree, g_object_ref (actor));
1924 for (i = event_tree->len - 1; i >= 0; i--)
1925 if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, TRUE))
1929 for (i = 0; i < event_tree->len; i++)
1930 if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, FALSE))
1934 for (i = 0; i < event_tree->len; i++)
1935 g_object_unref (g_ptr_array_index (event_tree, i));
1937 g_ptr_array_free (event_tree, TRUE);
1943 * Emits a pointer event after having prepared the event for delivery (setting
1944 * source, computing click_count, generating enter/leave etc.).
1948 emit_pointer_event (ClutterEvent *event,
1949 ClutterInputDevice *device)
1951 /* Using the global variable directly, since it has to be initialized
1954 ClutterMainContext *context = ClutterCntx;
1956 if (G_UNLIKELY (context->pointer_grab_actor != NULL &&
1960 clutter_actor_event (context->pointer_grab_actor, event, FALSE);
1962 else if (G_UNLIKELY (device != NULL &&
1963 device->pointer_grab_actor != NULL))
1965 /* per device grab */
1966 clutter_actor_event (device->pointer_grab_actor, event, FALSE);
1970 /* no grab, time to capture and bubble */
1971 emit_event (event, FALSE);
1976 emit_keyboard_event (ClutterEvent *event)
1978 ClutterMainContext *context = ClutterCntx;
1980 if (G_UNLIKELY (context->keyboard_grab_actor != NULL))
1981 clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
1983 emit_event (event, TRUE);
1987 unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
1989 ClutterMainContext *context = ClutterCntx;
1992 context->motion_last_actor = NULL;
1994 dev->motion_last_actor = NULL;
1998 set_motion_last_actor (ClutterActor *motion_current_actor,
1999 ClutterInputDevice *device)
2001 ClutterMainContext *context = ClutterCntx;
2002 ClutterActor *last_actor = context->motion_last_actor;
2005 last_actor = device->motion_last_actor;
2007 if (last_actor && last_actor != motion_current_actor)
2009 g_signal_handlers_disconnect_by_func
2011 G_CALLBACK (unset_motion_last_actor),
2015 if (motion_current_actor && last_actor != motion_current_actor)
2017 g_signal_connect (motion_current_actor, "destroy",
2018 G_CALLBACK (unset_motion_last_actor),
2023 device->motion_last_actor = motion_current_actor;
2025 context->motion_last_actor = motion_current_actor;
2029 generate_enter_leave_events (ClutterEvent *event)
2031 ClutterMainContext *context = ClutterCntx;
2032 ClutterActor *motion_current_actor = event->motion.source;
2033 ClutterActor *last_actor = context->motion_last_actor;
2034 ClutterInputDevice *device = clutter_event_get_device (event);
2037 last_actor = device->motion_last_actor;
2039 if (last_actor != motion_current_actor)
2041 if (motion_current_actor)
2046 cev.crossing.device = device;
2047 clutter_event_get_coords (event, &x, &y);
2049 if (context->motion_last_actor)
2051 cev.crossing.type = CLUTTER_LEAVE;
2052 cev.crossing.time = event->any.time;
2053 cev.crossing.flags = 0;
2056 cev.crossing.source = last_actor;
2057 cev.crossing.stage = event->any.stage;
2058 cev.crossing.related = motion_current_actor;
2060 emit_pointer_event (&cev, device);
2063 cev.crossing.type = CLUTTER_ENTER;
2064 cev.crossing.time = event->any.time;
2065 cev.crossing.flags = 0;
2068 cev.crossing.source = motion_current_actor;
2069 cev.crossing.stage = event->any.stage;
2071 if (context->motion_last_actor)
2072 cev.crossing.related = last_actor;
2074 cev.crossing.related = NULL;
2076 emit_pointer_event (&cev, device);
2080 set_motion_last_actor (motion_current_actor, device);
2085 * @event: a #ClutterEvent.
2087 * Processes an event. This function should never be called by applications.
2092 clutter_do_event (ClutterEvent *event)
2094 if (!event->any.stage)
2097 /* Instead of processing events when received, we queue them up to
2098 * handle per-frame before animations, layout, and drawing.
2100 * This gives us the chance to reliably compress motion events
2101 * because we've "looked ahead" and know all motion events that
2102 * will occur before drawing the frame.
2104 _clutter_stage_queue_event (event->any.stage, event);
2108 * _clutter_process_event
2109 * @event: a #ClutterEvent.
2111 * Does the actual work of processing an event that was queued earlier
2112 * out of clutter_do_event().
2115 _clutter_process_event (ClutterEvent *event)
2117 /* FIXME: This should probably be clutter_cook_event() - it would
2118 * take a raw event from the backend and 'cook' it so its more tasty.
2121 ClutterMainContext *context;
2122 ClutterBackend *backend;
2123 ClutterActor *stage;
2124 ClutterInputDevice *device = NULL;
2126 context = _clutter_context_get_default ();
2127 backend = context->backend;
2128 stage = CLUTTER_ACTOR(event->any.stage);
2133 CLUTTER_TIMESTAMP (EVENT, "Event received");
2135 context->last_event_time = clutter_event_get_time (event);
2137 switch (event->type)
2139 case CLUTTER_NOTHING:
2140 event->any.source = stage;
2144 /* The source is set for generated events, not for events
2145 * resulting from the cursor leaving the stage
2147 if (event->any.source == NULL)
2149 ClutterActor *last_actor = context->motion_last_actor;
2151 if (event->crossing.device != NULL)
2152 last_actor = event->crossing.device->motion_last_actor;
2154 event->any.source = last_actor;
2156 set_motion_last_actor (NULL, event->crossing.device);
2160 emit_pointer_event (event, event->crossing.device);
2163 case CLUTTER_DESTROY_NOTIFY:
2164 case CLUTTER_DELETE:
2165 event->any.source = stage;
2166 /* the stage did not handle the event, so we just quit */
2167 if (!clutter_stage_event (CLUTTER_STAGE (stage), event))
2169 if (stage == clutter_stage_get_default())
2170 clutter_main_quit ();
2172 clutter_actor_destroy (stage);
2177 case CLUTTER_KEY_PRESS:
2178 case CLUTTER_KEY_RELEASE:
2180 ClutterActor *actor = NULL;
2182 /* check that we're not a synthetic event with source set */
2183 if (event->any.source == NULL)
2185 actor = clutter_stage_get_key_focus (CLUTTER_STAGE (stage));
2186 event->any.source = actor;
2187 if (G_UNLIKELY (actor == NULL))
2189 g_warning ("No key focus set, discarding");
2194 emit_keyboard_event (event);
2198 case CLUTTER_MOTION:
2199 device = event->motion.device;
2201 /* Only stage gets motion events if clutter_set_motion_events is TRUE,
2202 * and the event is not a synthetic event with source set.
2204 if (!context->motion_events_per_actor &&
2205 event->any.source == NULL)
2207 /* Only stage gets motion events */
2208 event->any.source = stage;
2211 if (context->pointer_grab_actor != NULL)
2213 clutter_actor_event (context->pointer_grab_actor,
2217 else if (device != NULL && device->pointer_grab_actor != NULL)
2219 clutter_actor_event (device->pointer_grab_actor,
2224 /* Trigger handlers on stage in both capture .. */
2225 if (!clutter_actor_event (stage, event, TRUE))
2227 /* and bubbling phase */
2228 clutter_actor_event (stage, event, FALSE);
2235 case CLUTTER_BUTTON_PRESS:
2236 case CLUTTER_BUTTON_RELEASE:
2237 case CLUTTER_SCROLL:
2239 ClutterActor *actor;
2242 clutter_event_get_coords (event, &x, &y);
2244 /* Only do a pick to find the source if source is not already set
2245 * (as it could be in a synthetic event)
2247 if (event->any.source == NULL)
2249 /* Handle release off stage */
2250 if ((x >= clutter_actor_get_width (stage) ||
2251 y >= clutter_actor_get_height (stage) ||
2254 if (event->type == CLUTTER_BUTTON_RELEASE)
2256 CLUTTER_NOTE (EVENT,
2257 "Release off stage received at %.2f, %.2f",
2260 event->button.source = stage;
2261 emit_pointer_event (event, event->button.device);
2266 /* Map the event to a reactive actor */
2267 actor = _clutter_do_pick (CLUTTER_STAGE (stage),
2269 CLUTTER_PICK_REACTIVE);
2271 event->any.source = actor;
2277 /* use the source already set in the synthetic event */
2278 actor = event->any.source;
2282 /* FIXME: for an optimisation should check if there are
2283 * actually any reactive actors and avoid the pick all together
2284 * (signalling just the stage). Should be big help for gles.
2287 CLUTTER_NOTE (EVENT,
2288 "Reactive event received at %.2f, %.2f - actor: %p",
2292 /* Create, enter/leave events if needed */
2293 generate_enter_leave_events (event);
2295 if (event->type != CLUTTER_MOTION)
2297 /* Generate click count */
2298 event_click_count_generate (event);
2303 switch (event->type)
2305 case CLUTTER_BUTTON_PRESS:
2306 case CLUTTER_BUTTON_RELEASE:
2307 device = event->button.device;
2309 case CLUTTER_SCROLL:
2310 device = event->scroll.device;
2312 case CLUTTER_MOTION:
2313 /* already handled in the MOTION case of the switch */
2319 emit_pointer_event (event, device);
2323 case CLUTTER_STAGE_STATE:
2324 /* fullscreen / focus - forward to stage */
2325 event->any.source = stage;
2326 clutter_stage_event (CLUTTER_STAGE (stage), event);
2329 case CLUTTER_CLIENT_MESSAGE:
2335 * clutter_get_actor_by_gid
2336 * @id: a #ClutterActor ID.
2338 * Retrieves the #ClutterActor with @id.
2340 * Return value: (transfer none): the actor with the passed id or %NULL.
2341 * The returned actor does not have its reference count increased.
2346 clutter_get_actor_by_gid (guint32 id)
2348 ClutterMainContext *context;
2350 context = _clutter_context_get_default ();
2352 g_return_val_if_fail (context != NULL, NULL);
2354 return CLUTTER_ACTOR (clutter_id_pool_lookup (context->id_pool, id));
2358 clutter_base_init (void)
2360 static gboolean initialised = FALSE;
2364 GType foo; /* Quiet gcc */
2368 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2369 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2371 /* initialise GLib type system */
2374 /* CLUTTER_TYPE_ACTOR */
2375 foo = clutter_actor_get_type ();
2380 * clutter_get_default_frame_rate:
2382 * Retrieves the default frame rate. See clutter_set_default_frame_rate().
2384 * Return value: the default frame rate
2389 clutter_get_default_frame_rate (void)
2391 ClutterMainContext *context;
2393 context = _clutter_context_get_default ();
2395 return context->frame_rate;
2399 * clutter_set_default_frame_rate:
2400 * @frames_per_sec: the new default frame rate
2402 * Sets the default frame rate. This frame rate will be used to limit
2403 * the number of frames drawn if Clutter is not able to synchronize
2404 * with the vertical refresh rate of the display. When synchronization
2405 * is possible, this value is ignored.
2410 clutter_set_default_frame_rate (guint frames_per_sec)
2412 ClutterMainContext *context;
2414 context = _clutter_context_get_default ();
2416 if (context->frame_rate != frames_per_sec)
2417 context->frame_rate = frames_per_sec;
2422 on_pointer_grab_weak_notify (gpointer data,
2423 GObject *where_the_object_was)
2425 ClutterInputDevice *dev = (ClutterInputDevice *)data;
2426 ClutterMainContext *context;
2428 context = _clutter_context_get_default ();
2432 dev->pointer_grab_actor = NULL;
2433 clutter_ungrab_pointer_for_device (dev->id);
2437 context->pointer_grab_actor = NULL;
2438 clutter_ungrab_pointer ();
2443 * clutter_grab_pointer:
2444 * @actor: a #ClutterActor
2446 * Grabs pointer events, after the grab is done all pointer related events
2447 * (press, motion, release, enter, leave and scroll) are delivered to this
2448 * actor directly without passing through both capture and bubble phases of
2449 * the event delivery chain. The source set in the event will be the actor
2450 * that would have received the event if the pointer grab was not in effect.
2452 * <note><para>Grabs completely override the entire event delivery chain
2453 * done by Clutter. Pointer grabs should only be used as a last resource;
2454 * using the #ClutterActor::captured-event signal should always be the
2455 * preferred way to intercept event delivery to reactive actors.</para></note>
2457 * If you wish to grab all the pointer events for a specific input device,
2458 * you should use clutter_grab_pointer_for_device().
2463 clutter_grab_pointer (ClutterActor *actor)
2465 ClutterMainContext *context;
2467 g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2469 context = _clutter_context_get_default ();
2471 if (context->pointer_grab_actor == actor)
2474 if (context->pointer_grab_actor)
2476 g_object_weak_unref (G_OBJECT (context->pointer_grab_actor),
2477 on_pointer_grab_weak_notify,
2479 context->pointer_grab_actor = NULL;
2484 context->pointer_grab_actor = actor;
2486 g_object_weak_ref (G_OBJECT (actor),
2487 on_pointer_grab_weak_notify,
2493 * clutter_grab_pointer_for_device:
2494 * @actor: a #ClutterActor
2495 * @id: a device id, or -1
2497 * Grabs all the pointer events coming from the device @id for @actor.
2499 * If @id is -1 then this function is equivalent to clutter_grab_pointer().
2504 clutter_grab_pointer_for_device (ClutterActor *actor,
2507 ClutterInputDevice *dev;
2509 g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2511 /* essentially a global grab */
2514 clutter_grab_pointer (actor);
2518 dev = clutter_get_input_device_for_id (id);
2523 if (dev->pointer_grab_actor == actor)
2526 if (dev->pointer_grab_actor)
2528 g_object_weak_unref (G_OBJECT (dev->pointer_grab_actor),
2529 on_pointer_grab_weak_notify,
2531 dev->pointer_grab_actor = NULL;
2536 dev->pointer_grab_actor = actor;
2538 g_object_weak_ref (G_OBJECT (actor),
2539 on_pointer_grab_weak_notify,
2546 * clutter_ungrab_pointer:
2548 * Removes an existing grab of the pointer.
2553 clutter_ungrab_pointer (void)
2555 clutter_grab_pointer (NULL);
2559 * clutter_ungrab_pointer_for_device:
2562 * Removes an existing grab of the pointer events for device @id.
2567 clutter_ungrab_pointer_for_device (gint id)
2569 clutter_grab_pointer_for_device (NULL, id);
2574 * clutter_get_pointer_grab:
2576 * Queries the current pointer grab of clutter.
2578 * Return value: (transfer none): the actor currently holding the pointer grab, or NULL if there is no grab.
2583 clutter_get_pointer_grab (void)
2585 ClutterMainContext *context;
2586 context = _clutter_context_get_default ();
2588 return context->pointer_grab_actor;
2593 on_keyboard_grab_weak_notify (gpointer data,
2594 GObject *where_the_object_was)
2596 ClutterMainContext *context;
2598 context = _clutter_context_get_default ();
2599 context->keyboard_grab_actor = NULL;
2601 clutter_ungrab_keyboard ();
2605 * clutter_grab_keyboard:
2606 * @actor: a #ClutterActor
2608 * Grabs keyboard events, after the grab is done keyboard
2609 * events (#ClutterActor::key-press-event and #ClutterActor::key-release-event)
2610 * are delivered to this actor directly. The source set in the event will be
2611 * the actor that would have received the event if the keyboard grab was not
2614 * Like pointer grabs, keyboard grabs should only be used as a last
2617 * See also clutter_stage_set_key_focus() and clutter_actor_grab_key_focus()
2618 * to perform a "soft" key grab and assign key focus to a specific actor.
2623 clutter_grab_keyboard (ClutterActor *actor)
2625 ClutterMainContext *context;
2627 g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2629 context = _clutter_context_get_default ();
2631 if (context->keyboard_grab_actor == actor)
2634 if (context->keyboard_grab_actor)
2636 g_object_weak_unref (G_OBJECT (context->keyboard_grab_actor),
2637 on_keyboard_grab_weak_notify,
2639 context->keyboard_grab_actor = NULL;
2644 context->keyboard_grab_actor = actor;
2646 g_object_weak_ref (G_OBJECT (actor),
2647 on_keyboard_grab_weak_notify,
2653 * clutter_ungrab_keyboard:
2655 * Removes an existing grab of the keyboard.
2660 clutter_ungrab_keyboard (void)
2662 clutter_grab_keyboard (NULL);
2666 * clutter_get_keyboard_grab:
2668 * Queries the current keyboard grab of clutter.
2670 * Return value: (transfer none): the actor currently holding the keyboard grab, or NULL if there is no grab.
2675 clutter_get_keyboard_grab (void)
2677 ClutterMainContext *context;
2679 context = _clutter_context_get_default ();
2681 return context->keyboard_grab_actor;
2685 * clutter_clear_glyph_cache:
2687 * Clears the internal cache of glyphs used by the Pango
2688 * renderer. This will free up some memory and GL texture
2689 * resources. The cache will be automatically refilled as more text is
2695 clutter_clear_glyph_cache (void)
2697 if (CLUTTER_CONTEXT ()->font_map)
2698 cogl_pango_font_map_clear_glyph_cache (CLUTTER_CONTEXT ()->font_map);
2702 * clutter_set_font_flags:
2703 * @flags: The new flags
2705 * Sets the font quality options for subsequent text rendering
2708 * Using mipmapped textures will improve the quality for scaled down
2709 * text but will use more texture memory.
2711 * Enabling hinting improves text quality for static text but may
2712 * introduce some artifacts if the text is animated.
2717 clutter_set_font_flags (ClutterFontFlags flags)
2719 ClutterFontFlags old_flags, changed_flags;
2720 const cairo_font_options_t *font_options;
2721 cairo_font_options_t *new_font_options;
2722 ClutterBackend *backend;
2724 backend = clutter_get_default_backend ();
2726 if (CLUTTER_CONTEXT ()->font_map)
2727 cogl_pango_font_map_set_use_mipmapping (CLUTTER_CONTEXT ()->font_map,
2729 & CLUTTER_FONT_MIPMAPPING) != 0);
2731 old_flags = clutter_get_font_flags ();
2733 font_options = clutter_backend_get_font_options (backend);
2734 new_font_options = cairo_font_options_copy (font_options);
2736 /* Only set the font options that have actually changed so we don't
2737 override a detailed setting from the backend */
2738 changed_flags = old_flags ^ flags;
2740 if ((changed_flags & CLUTTER_FONT_HINTING))
2741 cairo_font_options_set_hint_style (new_font_options,
2742 (flags & CLUTTER_FONT_HINTING)
2743 ? CAIRO_HINT_STYLE_FULL
2744 : CAIRO_HINT_STYLE_NONE);
2746 clutter_backend_set_font_options (backend, new_font_options);
2748 cairo_font_options_destroy (new_font_options);
2750 if (CLUTTER_CONTEXT ()->pango_context)
2751 update_pango_context (backend, CLUTTER_CONTEXT ()->pango_context);
2755 * clutter_get_font_flags:
2757 * Gets the current font flags for rendering text. See
2758 * clutter_set_font_flags().
2760 * Return value: The font flags
2765 clutter_get_font_flags (void)
2767 ClutterMainContext *ctxt = CLUTTER_CONTEXT ();
2768 CoglPangoFontMap *font_map = NULL;
2769 const cairo_font_options_t *font_options;
2770 ClutterFontFlags flags = 0;
2772 font_map = CLUTTER_CONTEXT ()->font_map;
2774 if (G_LIKELY (font_map)
2775 && cogl_pango_font_map_get_use_mipmapping (font_map))
2776 flags |= CLUTTER_FONT_MIPMAPPING;
2778 font_options = clutter_backend_get_font_options (ctxt->backend);
2780 if ((cairo_font_options_get_hint_style (font_options)
2781 != CAIRO_HINT_STYLE_DEFAULT)
2782 && (cairo_font_options_get_hint_style (font_options)
2783 != CAIRO_HINT_STYLE_NONE))
2784 flags |= CLUTTER_FONT_HINTING;
2790 * clutter_get_input_device_for_id:
2793 * Retrieves the #ClutterInputDevice from its id.
2795 * Return value: (transfer none): a #ClutterInputDevice, or %NULL
2799 ClutterInputDevice *
2800 clutter_get_input_device_for_id (gint id)
2803 ClutterInputDevice *device = NULL;
2804 ClutterMainContext *context;
2806 context = _clutter_context_get_default ();
2808 for (item = context->input_devices;
2812 device = item->data;
2814 if (device->id == id)
2822 * clutter_get_font_map:
2824 * Retrieves the #PangoFontMap instance used by Clutter.
2825 * You can use the global font map object with the COGL
2828 * Return value: (transfer none): the #PangoFontMap instance. The returned
2829 * value is owned by Clutter and it should never be unreferenced.
2834 clutter_get_font_map (void)
2836 if (CLUTTER_CONTEXT ()->font_map)
2837 return PANGO_FONT_MAP (CLUTTER_CONTEXT ()->font_map);
2842 typedef struct _ClutterRepaintFunction
2847 GDestroyNotify notify;
2848 } ClutterRepaintFunction;
2851 * clutter_threads_remove_repaint_func:
2852 * @handle_id: an unsigned integer greater than zero
2854 * Removes the repaint function with @handle_id as its id
2859 clutter_threads_remove_repaint_func (guint handle_id)
2861 ClutterRepaintFunction *repaint_func;
2862 ClutterMainContext *context;
2865 g_return_if_fail (handle_id > 0);
2867 context = CLUTTER_CONTEXT ();
2868 l = context->repaint_funcs;
2871 repaint_func = l->data;
2873 if (repaint_func->id == handle_id)
2875 context->repaint_funcs =
2876 g_list_remove_link (context->repaint_funcs, l);
2880 if (repaint_func->notify)
2881 repaint_func->notify (repaint_func->data);
2883 g_slice_free (ClutterRepaintFunction, repaint_func);
2893 * clutter_threads_add_repaint_func:
2894 * @func: the function to be called within the paint cycle
2895 * @data: data to be passed to the function, or %NULL
2896 * @notify: function to be called when removing the repaint
2897 * function, or %NULL
2899 * Adds a function to be called whenever Clutter is repainting a Stage.
2900 * If the function returns %FALSE it is automatically removed from the
2901 * list of repaint functions and will not be called again.
2903 * This function is guaranteed to be called from within the same thread
2904 * that called clutter_main(), and while the Clutter lock is being held.
2906 * A repaint function is useful to ensure that an update of the scenegraph
2907 * is performed before the scenegraph is repainted; for instance, uploading
2908 * a frame from a video into a #ClutterTexture.
2910 * When the repaint function is removed (either because it returned %FALSE
2911 * or because clutter_threads_remove_repaint_func() has been called) the
2912 * @notify function will be called, if any is set.
2914 * Return value: the ID (greater than 0) of the repaint function. You
2915 * can use the returned integer to remove the repaint function by
2916 * calling clutter_threads_remove_repaint_func().
2921 clutter_threads_add_repaint_func (GSourceFunc func,
2923 GDestroyNotify notify)
2925 static guint repaint_id = 1;
2926 ClutterMainContext *context;
2927 ClutterRepaintFunction *repaint_func;
2929 g_return_val_if_fail (func != NULL, 0);
2931 context = CLUTTER_CONTEXT ();
2933 /* XXX lock the context */
2935 repaint_func = g_slice_new (ClutterRepaintFunction);
2937 repaint_func->id = repaint_id++;
2938 repaint_func->func = func;
2939 repaint_func->data = data;
2940 repaint_func->notify = notify;
2942 context->repaint_funcs = g_list_prepend (context->repaint_funcs,
2945 /* XXX unlock the context */
2947 return repaint_func->id;
2951 * _clutter_run_repaint_functions:
2953 * Executes the repaint functions added using the
2954 * clutter_threads_add_repaint_func() function.
2956 * Must be called before calling clutter_redraw() and
2957 * with the Clutter thread lock held.
2960 _clutter_run_repaint_functions (void)
2962 ClutterMainContext *context = CLUTTER_CONTEXT ();
2963 ClutterRepaintFunction *repaint_func;
2964 GList *reinvoke_list, *l;
2966 if (context->repaint_funcs == NULL)
2969 reinvoke_list = NULL;
2971 /* consume the whole list while we execute the functions */
2972 while (context->repaint_funcs)
2974 gboolean res = FALSE;
2976 repaint_func = context->repaint_funcs->data;
2978 l = context->repaint_funcs;
2979 context->repaint_funcs =
2980 g_list_remove_link (context->repaint_funcs, context->repaint_funcs);
2984 res = repaint_func->func (repaint_func->data);
2987 reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
2990 if (repaint_func->notify)
2991 repaint_func->notify (repaint_func->data);
2993 g_slice_free (ClutterRepaintFunction, repaint_func);
2998 context->repaint_funcs = reinvoke_list;
3002 * clutter_check_version:
3003 * @major: major version, like 1 in 1.2.3
3004 * @minor: minor version, like 2 in 1.2.3
3005 * @micro: micro version, like 3 in 1.2.3
3007 * Run-time version check, to check the version the Clutter library
3008 * that an application is currently linked against
3010 * This is the run-time equivalent of the compile-time %CLUTTER_CHECK_VERSION
3011 * pre-processor macro
3013 * Return value: %TRUE if the version of the Clutter library is
3014 * greater than (@major, @minor, @micro), and %FALSE otherwise
3019 clutter_check_version (guint major,
3023 return (clutter_major_version > major ||
3024 (clutter_major_version == major &&
3025 clutter_minor_version > minor) ||
3026 (clutter_major_version == major &&
3027 clutter_minor_version == minor &&
3028 clutter_micro_version >= micro));