Merge branch 'generic-actor-clone'
[profile/ivi/clutter.git] / clutter / clutter-main.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
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.
14  *
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.
19  *
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.
24  */
25 /**
26  * SECTION:clutter-main
27  * @short_description: Various 'global' clutter functions.
28  *
29  * Functions to retrieve various global Clutter resources and other utility
30  * functions for mainloops, events and threads
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdlib.h>
38 #include <glib/gi18n-lib.h>
39 #include <locale.h>
40
41 #include "clutter-event.h"
42 #include "clutter-backend.h"
43 #include "clutter-main.h"
44 #include "clutter-feature.h"
45 #include "clutter-actor.h"
46 #include "clutter-stage.h"
47 #include "clutter-private.h"
48 #include "clutter-debug.h"
49 #include "clutter-version.h"    /* For flavour define */
50 #include "clutter-frame-source.h"
51
52 #include "cogl/cogl.h"
53 #include "pango/cogl-pango.h"
54
55 /* main context */
56 static ClutterMainContext *ClutterCntx       = NULL;
57
58 /* main lock and locking/unlocking functions */
59 static GMutex *clutter_threads_mutex         = NULL;
60 static GCallback clutter_threads_lock        = NULL;
61 static GCallback clutter_threads_unlock      = NULL;
62
63 static gboolean clutter_is_initialized       = FALSE;
64 static gboolean clutter_show_fps             = FALSE;
65 static gboolean clutter_fatal_warnings       = FALSE;
66
67 static guint clutter_default_fps             = 60;
68
69 static guint clutter_main_loop_level         = 0;
70 static GSList *main_loops                    = NULL;
71
72 static PangoDirection clutter_text_direction = PANGO_DIRECTION_LTR;
73
74 guint clutter_debug_flags = 0;  /* global clutter debug flag */
75
76 #ifdef CLUTTER_ENABLE_DEBUG
77 static const GDebugKey clutter_debug_keys[] = {
78   { "misc", CLUTTER_DEBUG_MISC },
79   { "actor", CLUTTER_DEBUG_ACTOR },
80   { "texture", CLUTTER_DEBUG_TEXTURE },
81   { "event", CLUTTER_DEBUG_EVENT },
82   { "paint", CLUTTER_DEBUG_PAINT },
83   { "gl", CLUTTER_DEBUG_GL },
84   { "alpha", CLUTTER_DEBUG_ALPHA },
85   { "behaviour", CLUTTER_DEBUG_BEHAVIOUR },
86   { "pango", CLUTTER_DEBUG_PANGO },
87   { "backend", CLUTTER_DEBUG_BACKEND },
88   { "scheduler", CLUTTER_DEBUG_SCHEDULER },
89   { "script", CLUTTER_DEBUG_SCRIPT },
90   { "shader", CLUTTER_DEBUG_SHADER },
91   { "multistage", CLUTTER_DEBUG_MULTISTAGE },
92   { "animation", CLUTTER_DEBUG_ANIMATION }
93 };
94 #endif /* CLUTTER_ENABLE_DEBUG */
95
96 /**
97  * clutter_get_show_fps:
98  *
99  * Returns whether Clutter should print out the frames per second on the
100  * console. You can enable this setting either using the
101  * <literal>CLUTTER_SHOW_FPS</literal> environment variable or passing
102  * the <literal>--clutter-show-fps</literal> command line argument. *
103  *
104  * Return value: %TRUE if Clutter should show the FPS.
105  *
106  * Since: 0.4
107  */
108 gboolean
109 clutter_get_show_fps (void)
110 {
111   return clutter_show_fps;
112 }
113
114 void
115 _clutter_stage_maybe_relayout (ClutterActor *stage)
116 {
117   ClutterUnit natural_width, natural_height;
118   ClutterActorBox box = { 0, };
119
120   /* avoid reentrancy */
121   if (!(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_RELAYOUT))
122     {
123       CLUTTER_NOTE (ACTOR, "Recomputing layout");
124
125       CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
126
127       natural_width = natural_height = 0;
128       clutter_actor_get_preferred_size (stage,
129                                         NULL, NULL,
130                                         &natural_width, &natural_height);
131
132       box.x1 = 0;
133       box.y1 = 0;
134       box.x2 = natural_width;
135       box.y2 = natural_height;
136
137       CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
138                     CLUTTER_UNITS_TO_DEVICE (natural_width),
139                     CLUTTER_UNITS_TO_DEVICE (natural_height));
140
141       clutter_actor_allocate (stage, &box, FALSE);
142
143       CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IN_RELAYOUT);
144     }
145 }
146
147 void
148 _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
149 {
150   if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
151     {
152       ClutterPerspective perspective;
153       guint width, height;
154
155       clutter_actor_get_size (CLUTTER_ACTOR (stage), &width, &height);
156       clutter_stage_get_perspectivex (stage, &perspective);
157
158       CLUTTER_NOTE (PAINT, "Setting up the viewport");
159
160       cogl_setup_viewport (width, height,
161                            perspective.fovy,
162                            perspective.aspect,
163                            perspective.z_near,
164                            perspective.z_far);
165
166       CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
167     }
168 }
169
170 /**
171  * clutter_redraw:
172  *
173  * Forces a redraw of the entire stage. Applications should never use this
174  * function, but queue a redraw using clutter_actor_queue_redraw().
175  */
176 void
177 clutter_redraw (ClutterStage *stage)
178 {
179   ClutterMainContext *ctx;
180   static GTimer      *timer = NULL;
181   static guint        timer_n_frames = 0;
182
183   ctx  = clutter_context_get_default ();
184
185   CLUTTER_TIMESTAMP (SCHEDULER, "Redraw start for stage:%p", stage);
186   CLUTTER_NOTE (PAINT, " Redraw enter for stage:%p", stage);
187   CLUTTER_NOTE (MULTISTAGE, "Redraw called for stage:%p", stage);
188
189   /* Before we can paint, we have to be sure we have the latest layout */
190   _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
191
192   _clutter_backend_ensure_context (ctx->backend, stage);
193
194   /* Setup FPS count - not currently across *all* stages rather than per */
195   if (G_UNLIKELY (clutter_get_show_fps ()))
196     {
197       if (!timer)
198         timer = g_timer_new ();
199     }
200
201   /* The code below can't go in stage paint as base actor_paint
202    * will get called before it (and break picking, etc)
203    */
204   _clutter_stage_maybe_setup_viewport (stage);
205
206   /* Call through to the actual backend to do the painting down from
207    * the stage. It will likely need to swap buffers, vblank sync etc
208    * which will be windowing system dependant.
209   */
210   _clutter_backend_redraw (ctx->backend, stage);
211
212   /* Complete FPS info */
213   if (G_UNLIKELY (clutter_get_show_fps ()))
214     {
215       timer_n_frames++;
216
217       if (g_timer_elapsed (timer, NULL) >= 1.0)
218         {
219           g_print ("*** FPS: %i ***\n", timer_n_frames);
220           timer_n_frames = 0;
221           g_timer_start (timer);
222         }
223     }
224
225   CLUTTER_NOTE (PAINT, " Redraw leave for stage:%p", stage);
226   CLUTTER_TIMESTAMP (SCHEDULER, "Redraw finish for stage:%p", stage);
227 }
228
229 /**
230  * clutter_set_motion_events_enabled:
231  * @enable: %TRUE to enable per-actor motion events
232  *
233  * Sets whether per-actor motion events should be enabled or not (the
234  * default is to enable them).
235  *
236  * If @enable is %FALSE the following events will not work:
237  * <itemizedlist>
238  *   <listitem><para>ClutterActor::motion-event, unless on the
239  *     #ClutterStage</para></listitem>
240  *   <listitem><para>ClutterActor::enter-event</para></listitem>
241  *   <listitem><para>ClutterActor::leave-event</para></listitem>
242  * </itemizedlist>
243  *
244  * Since: 0.6
245  */
246 void
247 clutter_set_motion_events_enabled (gboolean enable)
248 {
249   ClutterMainContext *context = clutter_context_get_default ();
250
251   context->motion_events_per_actor = enable;
252 }
253
254 /**
255  * clutter_get_motion_events_enabled:
256  *
257  * Gets whether the per-actor motion events are enabled.
258  *
259  * Return value: %TRUE if the motion events are enabled
260  *
261  * Since: 0.6
262  */
263 gboolean
264 clutter_get_motion_events_enabled (void)
265 {
266   ClutterMainContext *context = clutter_context_get_default ();
267
268   return context->motion_events_per_actor;
269 }
270
271 guint _clutter_pix_to_id (guchar pixel[4]);
272
273 static inline void init_bits (void)
274 {
275   ClutterMainContext *ctx;
276
277   static gboolean done = FALSE;
278   if (G_LIKELY (done))
279     return;
280
281   ctx = clutter_context_get_default ();
282
283   done = TRUE;
284 }
285
286 void
287 _clutter_id_to_color (guint id, ClutterColor *col)
288 {
289   ClutterMainContext *ctx;
290   gint                red, green, blue;
291   ctx = clutter_context_get_default ();
292
293   /* compute the numbers we'll store in the components */
294   red   = (id >> (ctx->fb_g_mask_used+ctx->fb_b_mask_used))
295                 & (0xff >> (8-ctx->fb_r_mask_used));
296   green = (id >> ctx->fb_b_mask_used) & (0xff >> (8-ctx->fb_g_mask_used));
297   blue  = (id)  & (0xff >> (8-ctx->fb_b_mask_used));
298
299   /* shift left bits a bit and add one, this circumvents
300    * at least some potential rounding errors in GL/GLES
301    * driver / hw implementation.
302    */
303   if (ctx->fb_r_mask_used != ctx->fb_r_mask)
304     red = red * 2;
305   if (ctx->fb_g_mask_used != ctx->fb_g_mask)
306     green = green * 2;
307   if (ctx->fb_b_mask_used != ctx->fb_b_mask)
308     blue  = blue  * 2;
309
310   /* shift up to be full 8bit values */
311   red   = (red   << (8 - ctx->fb_r_mask)) | (0x7f >> (ctx->fb_r_mask_used));
312   green = (green << (8 - ctx->fb_g_mask)) | (0x7f >> (ctx->fb_g_mask_used));
313   blue  = (blue  << (8 - ctx->fb_b_mask)) | (0x7f >> (ctx->fb_b_mask_used));
314
315   col->red   = red;
316   col->green = green;
317   col->blue  = blue;
318   col->alpha = 0xff;
319 }
320
321 guint
322 _clutter_pixel_to_id (guchar pixel[4])
323 {
324   ClutterMainContext *ctx;
325   gint  red, green, blue;
326   guint id;
327
328   ctx = clutter_context_get_default ();
329
330   /* reduce the pixel components to the number of bits actually used of the
331    * 8bits.
332    */
333   red   = pixel[0] >> (8 - ctx->fb_r_mask);
334   green = pixel[1] >> (8 - ctx->fb_g_mask);
335   blue  = pixel[2] >> (8 - ctx->fb_b_mask);
336
337   /* divide potentially by two if 'fuzzy' */
338   red   = red   >> (ctx->fb_r_mask - ctx->fb_r_mask_used);
339   green = green >> (ctx->fb_g_mask - ctx->fb_g_mask_used);
340   blue  = blue  >> (ctx->fb_b_mask - ctx->fb_b_mask_used);
341
342   /* combine the correct per component values into the final id */
343   id =  blue + (green <<  ctx->fb_b_mask_used)
344           + (red << (ctx->fb_b_mask_used + ctx->fb_g_mask_used));
345
346   return id;
347 }
348
349 ClutterActor *
350 _clutter_do_pick (ClutterStage   *stage,
351                   gint            x,
352                   gint            y,
353                   ClutterPickMode mode)
354 {
355   ClutterMainContext *context;
356   guchar              pixel[4];
357   GLint               viewport[4];
358   CoglColor           white;
359   guint32             id;
360   GLboolean           dither_was_on;
361
362   context = clutter_context_get_default ();
363
364   _clutter_backend_ensure_context (context->backend, stage);
365
366   /* needed for when a context switch happens */
367   _clutter_stage_maybe_setup_viewport (stage);
368
369   cogl_color_set_from_4ub (&white, 255, 255, 255, 255);
370   cogl_paint_init (&white);
371
372   /* Disable dithering (if any) when doing the painting in pick mode */
373   dither_was_on = glIsEnabled (GL_DITHER);
374   glDisable (GL_DITHER);
375
376   /* Render the entire scence in pick mode - just single colored silhouette's
377    * are drawn offscreen (as we never swap buffers)
378   */
379   context->pick_mode = mode;
380   clutter_actor_paint (CLUTTER_ACTOR (stage));
381   context->pick_mode = CLUTTER_PICK_NONE;
382
383   /* Calls should work under both GL and GLES, note GLES needs RGBA */
384   glGetIntegerv(GL_VIEWPORT, viewport);
385
386   /* Below to be safe, particularly on GL ES. an EGL wait call or full
387    * could be nicer.
388   */
389   glFinish();
390
391   /* Read the color of the screen co-ords pixel */
392   glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
393
394   /* Restore whether GL_DITHER was enabled */
395   if (dither_was_on)
396     glEnable (GL_DITHER);
397
398   if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
399     return CLUTTER_ACTOR (stage);
400
401   id = _clutter_pixel_to_id (pixel);
402
403   return clutter_get_actor_by_gid (id);
404 }
405
406 static PangoDirection
407 clutter_get_text_direction (void)
408 {
409   PangoDirection dir = PANGO_DIRECTION_LTR;
410   const gchar *direction;
411
412   direction = g_getenv ("CLUTTER_TEXT_DIRECTION");
413   if (direction && *direction != '\0')
414     {
415       if (strcmp (direction, "rtl") == 0)
416         dir = PANGO_DIRECTION_RTL;
417       else if (strcmp (direction, "ltr") == 0)
418         dir = PANGO_DIRECTION_LTR;
419     }
420   else
421     {
422       /* Translate to default:RTL if you want your widgets
423        * to be RTL, otherwise translate to default:LTR.
424        *
425        * Do *not* translate it to "predefinito:LTR": if it
426        * it isn't default:LTR or default:RTL it will not work
427        */
428       char *e = _("default:LTR");
429
430       if (strcmp (e, "default:RTL") == 0)
431         dir = PANGO_DIRECTION_RTL;
432       else if (strcmp (e, "default:LTR") == 0)
433         dir = PANGO_DIRECTION_LTR;
434       else
435         g_warning ("Whoever translated default:LTR did so wrongly.");
436     }
437
438   return dir;
439 }
440
441 static void
442 update_pango_context (ClutterBackend *backend,
443                       PangoContext   *context)
444 {
445   PangoFontDescription *font_desc;
446   cairo_font_options_t *font_options;
447   const gchar *font_name;
448   gdouble resolution;
449
450   /* update the text direction */
451   pango_context_set_base_dir (context, clutter_text_direction);
452
453   /* get the configuration for the PangoContext from the backend */
454   font_name = clutter_backend_get_font_name (backend);
455   font_options = clutter_backend_get_font_options (backend);
456   font_options = cairo_font_options_copy (font_options);
457   resolution = clutter_backend_get_resolution (backend);
458
459   font_desc = pango_font_description_from_string (font_name);
460
461   if (resolution < 0)
462     resolution = 96.0; /* fall back */
463
464   if (CLUTTER_CONTEXT ()->user_font_options)
465     cairo_font_options_merge (font_options,
466                               CLUTTER_CONTEXT ()->user_font_options);
467
468   pango_context_set_font_description (context, font_desc);
469   pango_cairo_context_set_font_options (context, font_options);
470   cairo_font_options_destroy (font_options);
471   pango_cairo_context_set_resolution (context, resolution);
472
473   pango_font_description_free (font_desc);
474 }
475
476 PangoContext *
477 _clutter_context_get_pango_context (ClutterMainContext *self)
478 {
479   if (G_UNLIKELY (self->pango_context == NULL))
480     {
481       PangoContext *context;
482
483       context = cogl_pango_font_map_create_context (self->font_map);
484       self->pango_context = context;
485
486       g_signal_connect (self->backend, "resolution-changed",
487                         G_CALLBACK (update_pango_context),
488                         self->pango_context);
489       g_signal_connect (self->backend, "font-changed",
490                         G_CALLBACK (update_pango_context),
491                         self->pango_context);
492     }
493
494   update_pango_context (self->backend, self->pango_context);
495
496   return self->pango_context;
497 }
498
499 PangoContext *
500 _clutter_context_create_pango_context (ClutterMainContext *self)
501 {
502   PangoContext *context;
503
504   context = cogl_pango_font_map_create_context (self->font_map);
505   update_pango_context (self->backend, context);
506
507   return context;
508 }
509
510 /**
511  * clutter_main_quit:
512  *
513  * Terminates the Clutter mainloop.
514  */
515 void
516 clutter_main_quit (void)
517 {
518   g_return_if_fail (main_loops != NULL);
519
520   g_main_loop_quit (main_loops->data);
521 }
522
523 /**
524  * clutter_main_level:
525  *
526  * Retrieves the depth of the Clutter mainloop.
527  *
528  * Return value: The level of the mainloop.
529  */
530 gint
531 clutter_main_level (void)
532 {
533   return clutter_main_loop_level;
534 }
535
536 /**
537  * clutter_main:
538  *
539  * Starts the Clutter mainloop.
540  */
541 void
542 clutter_main (void)
543 {
544   GMainLoop *loop;
545
546   /* Make sure there is a context */
547   CLUTTER_CONTEXT ();
548
549   if (!clutter_is_initialized)
550     {
551       g_warning ("Called clutter_main() but Clutter wasn't initialised.  "
552                  "You must call clutter_init() first.");
553       return;
554     }
555
556   CLUTTER_MARK ();
557
558   clutter_main_loop_level++;
559
560   loop = g_main_loop_new (NULL, TRUE);
561   main_loops = g_slist_prepend (main_loops, loop);
562
563 #ifdef HAVE_CLUTTER_FRUITY
564   /* clutter fruity creates an application that forwards events and manually
565    * spins the mainloop
566    */
567   clutter_fruity_main ();
568 #else
569   if (g_main_loop_is_running (main_loops->data))
570     {
571       clutter_threads_leave ();
572       g_main_loop_run (loop);
573       clutter_threads_enter ();
574     }
575 #endif
576
577   main_loops = g_slist_remove (main_loops, loop);
578
579   g_main_loop_unref (loop);
580
581   clutter_main_loop_level--;
582
583   CLUTTER_MARK ();
584 }
585
586 static void
587 clutter_threads_impl_lock (void)
588 {
589   if (clutter_threads_mutex)
590     g_mutex_lock (clutter_threads_mutex);
591 }
592
593 static void
594 clutter_threads_impl_unlock (void)
595 {
596   if (clutter_threads_mutex)
597     g_mutex_unlock (clutter_threads_mutex);
598 }
599
600 /**
601  * clutter_threads_init:
602  *
603  * Initialises the Clutter threading mechanism, so that Clutter API can be
604  * called by multiple threads, using clutter_threads_enter() and
605  * clutter_threads_leave() to mark the critical sections.
606  *
607  * You must call g_thread_init() before this function.
608  *
609  * This function must be called before clutter_init().
610  *
611  * Since: 0.4
612  */
613 void
614 clutter_threads_init (void)
615 {
616   if (!g_thread_supported ())
617     g_error ("g_thread_init() must be called before clutter_threads_init()");
618
619   clutter_threads_mutex = g_mutex_new ();
620
621   if (!clutter_threads_lock)
622     clutter_threads_lock = clutter_threads_impl_lock;
623
624   if (!clutter_threads_unlock)
625     clutter_threads_unlock = clutter_threads_impl_unlock;
626 }
627
628 /**
629  * clutter_threads_set_lock_functions:
630  * @enter_fn: function called when aquiring the Clutter main lock
631  * @leave_fn: function called when releasing the Clutter main lock
632  *
633  * Allows the application to replace the standard method that
634  * Clutter uses to protect its data structures. Normally, Clutter
635  * creates a single #GMutex that is locked by clutter_threads_enter(),
636  * and released by clutter_threads_leave(); using this function an
637  * application provides, instead, a function @enter_fn that is
638  * called by clutter_threads_enter() and a function @leave_fn that is
639  * called by clutter_threads_leave().
640  *
641  * The functions must provide at least same locking functionality
642  * as the default implementation, but can also do extra application
643  * specific processing.
644  *
645  * As an example, consider an application that has its own recursive
646  * lock that when held, holds the Clutter lock as well. When Clutter
647  * unlocks the Clutter lock when entering a recursive main loop, the
648  * application must temporarily release its lock as well.
649  *
650  * Most threaded Clutter apps won't need to use this method.
651  *
652  * This method must be called before clutter_threads_init(), and cannot
653  * be called multiple times.
654  *
655  * Since: 0.4
656  */
657 void
658 clutter_threads_set_lock_functions (GCallback enter_fn,
659                                     GCallback leave_fn)
660 {
661   g_return_if_fail (clutter_threads_lock == NULL &&
662                     clutter_threads_unlock == NULL);
663
664   clutter_threads_lock = enter_fn;
665   clutter_threads_unlock = leave_fn;
666 }
667
668 typedef struct
669 {
670   GSourceFunc func;
671   gpointer data;
672   GDestroyNotify notify;
673 } ClutterThreadsDispatch;
674
675 static gboolean
676 clutter_threads_dispatch (gpointer data)
677 {
678   ClutterThreadsDispatch *dispatch = data;
679   gboolean ret = FALSE;
680
681   clutter_threads_enter ();
682
683   if (!g_source_is_destroyed (g_main_current_source ()))
684     ret = dispatch->func (dispatch->data);
685
686   clutter_threads_leave ();
687
688   return ret;
689 }
690
691 static void
692 clutter_threads_dispatch_free (gpointer data)
693 {
694   ClutterThreadsDispatch *dispatch = data;
695
696   /* XXX - we cannot hold the thread lock here because the main loop
697    * might destroy a source while still in the dispatcher function; so
698    * knowing whether the lock is being held or not is not known a priori.
699    *
700    * see bug: http://bugzilla.gnome.org/show_bug.cgi?id=459555
701    */
702   if (dispatch->notify)
703     dispatch->notify (dispatch->data);
704
705   g_slice_free (ClutterThreadsDispatch, dispatch);
706 }
707
708 /**
709  * clutter_threads_add_idle_full:
710  * @priority: the priority of the timeout source. Typically this will be in the
711  *    range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
712  * @func: function to call
713  * @data: data to pass to the function
714  * @notify: functio to call when the idle source is removed
715  *
716  * Adds a function to be called whenever there are no higher priority
717  * events pending. If the function returns %FALSE it is automatically
718  * removed from the list of event sources and will not be called again.
719  *
720  * This function can be considered a thread-safe variant of g_idle_add_full():
721  * it will call @function while holding the Clutter lock. It is logically
722  * equivalent to the following implementation:
723  *
724  * |[
725  * static gboolean
726  * idle_safe_callback (gpointer data)
727  * {
728  *    SafeClosure *closure = data;
729  *    gboolean res = FALSE;
730  *
731  *    /&ast; mark the critical section &ast;/
732  *
733  *    clutter_threads_enter();
734  *
735  *    /&ast; the callback does not need to acquire the Clutter
736  *     &ast; lock itself, as it is held by the this proxy handler
737  *     &ast;/
738  *    res = closure->callback (closure->data);
739  *
740  *    clutter_threads_leave();
741  *
742  *    return res;
743  * }
744  * static gulong
745  * add_safe_idle (GSourceFunc callback,
746  *                gpointer    data)
747  * {
748  *   SafeClosure *closure = g_new0 (SafeClosure, 1);
749  *
750  *   closure-&gt;callback = callback;
751  *   closure-&gt;data = data;
752  *
753  *   return g_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
754  *                           idle_safe_callback,
755  *                           closure,
756  *                           g_free)
757  * }
758  *]|
759  *
760  * This function should be used by threaded applications to make sure
761  * that @func is emitted under the Clutter threads lock and invoked
762  * from the same thread that started the Clutter main loop. For instance,
763  * it can be used to update the UI using the results from a worker
764  * thread:
765  *
766  * |[
767  * static gboolean
768  * update_ui (gpointer data)
769  * {
770  *   SomeClosure *closure = data;
771  *
772  *   /&ast; it is safe to call Clutter API from this function because
773  *    &ast; it is invoked from the same thread that started the main
774  *    &ast; loop and under the Clutter thread lock
775  *    &ast;/
776  *   clutter_label_set_text (CLUTTER_LABEL (closure-&gt;label),
777  *                           closure-&gt;text);
778  *
779  *   g_object_unref (closure-&gt;label);
780  *   g_free (closure);
781  *
782  *   return FALSE;
783  * }
784  *
785  *   /&ast; within another thread &ast;/
786  *   closure = g_new0 (SomeClosure, 1);
787  *   /&ast; always take a reference on GObject instances &ast;/
788  *   closure-&gt;label = g_object_ref (my_application-&gt;label);
789  *   closure-&gt;text = g_strdup (processed_text_to_update_the_label);
790  *
791  *   clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE,
792  *                                  update_ui,
793  *                                  closure,
794  *                                  NULL);
795  * ]|
796  *
797  * Return value: the ID (greater than 0) of the event source.
798  *
799  * Since: 0.4
800  */
801 guint
802 clutter_threads_add_idle_full (gint           priority,
803                                GSourceFunc    func,
804                                gpointer       data,
805                                GDestroyNotify notify)
806 {
807   ClutterThreadsDispatch *dispatch;
808
809   g_return_val_if_fail (func != NULL, 0);
810
811   dispatch = g_slice_new (ClutterThreadsDispatch);
812   dispatch->func = func;
813   dispatch->data = data;
814   dispatch->notify = notify;
815
816   return g_idle_add_full (priority,
817                           clutter_threads_dispatch, dispatch,
818                           clutter_threads_dispatch_free);
819 }
820
821 /**
822  * clutter_threads_add_idle:
823  * @func: function to call
824  * @data: data to pass to the function
825  *
826  * Simple wrapper around clutter_threads_add_idle_full() using the
827  * default priority.
828  *
829  * Return value: the ID (greater than 0) of the event source.
830  *
831  * Since: 0.4
832  */
833 guint
834 clutter_threads_add_idle (GSourceFunc func,
835                           gpointer    data)
836 {
837   g_return_val_if_fail (func != NULL, 0);
838
839   return clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
840                                         func, data,
841                                         NULL);
842 }
843
844 /**
845  * clutter_threads_add_timeout_full:
846  * @priority: the priority of the timeout source. Typically this will be in the
847  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
848  * @interval: the time between calls to the function, in milliseconds
849  * @func: function to call
850  * @data: data to pass to the function
851  * @notify: function to call when the timeout source is removed
852  *
853  * Sets a function to be called at regular intervals holding the Clutter
854  * threads lock, with the given priority. The function is called repeatedly
855  * until it returns %FALSE, at which point the timeout is automatically
856  * removed and the function will not be called again. The @notify function
857  * is called when the timeout is removed.
858  *
859  * The first call to the function will be at the end of the first @interval.
860  *
861  * It is important to note that, due to how the Clutter main loop is
862  * implemented, the timing will not be accurate and it will not try to
863  * "keep up" with the interval. A more reliable source is available
864  * using clutter_threads_add_frame_source_full(), which is also internally
865  * used by #ClutterTimeline.
866  *
867  * See also clutter_threads_add_idle_full().
868  *
869  * Return value: the ID (greater than 0) of the event source.
870  *
871  * Since: 0.4
872  */
873 guint
874 clutter_threads_add_timeout_full (gint           priority,
875                                   guint          interval,
876                                   GSourceFunc    func,
877                                   gpointer       data,
878                                   GDestroyNotify notify)
879 {
880   ClutterThreadsDispatch *dispatch;
881
882   g_return_val_if_fail (func != NULL, 0);
883
884   dispatch = g_slice_new (ClutterThreadsDispatch);
885   dispatch->func = func;
886   dispatch->data = data;
887   dispatch->notify = notify;
888
889   return g_timeout_add_full (priority,
890                              interval,
891                              clutter_threads_dispatch, dispatch,
892                              clutter_threads_dispatch_free);
893 }
894
895 /**
896  * clutter_threads_add_timeout:
897  * @interval: the time between calls to the function, in milliseconds
898  * @func: function to call
899  * @data: data to pass to the function
900  *
901  * Simple wrapper around clutter_threads_add_timeout_full().
902  *
903  * Return value: the ID (greater than 0) of the event source.
904  *
905  * Since: 0.4
906  */
907 guint
908 clutter_threads_add_timeout (guint       interval,
909                              GSourceFunc func,
910                              gpointer    data)
911 {
912   g_return_val_if_fail (func != NULL, 0);
913
914   return clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT,
915                                            interval,
916                                            func, data,
917                                            NULL);
918 }
919
920 /**
921  * clutter_threads_add_frame_source_full:
922  * @priority: the priority of the frame source. Typically this will be in the
923  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
924  * @interval: the time between calls to the function, in milliseconds
925  * @func: function to call
926  * @data: data to pass to the function
927  * @notify: function to call when the timeout source is removed
928  *
929  * Sets a function to be called at regular intervals holding the Clutter
930  * threads lock, with the given priority. The function is called repeatedly
931  * until it returns %FALSE, at which point the timeout is automatically
932  * removed and the function will not be called again. The @notify function
933  * is called when the timeout is removed.
934  *
935  * This function is similar to clutter_threads_add_timeout_full()
936  * except that it will try to compensate for delays. For example, if
937  * @func takes half the interval time to execute then the function
938  * will be called again half the interval time after it finished. In
939  * contrast clutter_threads_add_timeout_full() would not fire until a
940  * full interval after the function completes so the delay between
941  * calls would be @interval * 1.5. This function does not however try
942  * to invoke the function multiple times to catch up missing frames if
943  * @func takes more than @interval ms to execute.
944  *
945  * See also clutter_threads_add_idle_full().
946  *
947  * Return value: the ID (greater than 0) of the event source.
948  *
949  * Since: 0.8
950  */
951 guint
952 clutter_threads_add_frame_source_full (gint           priority,
953                                        guint          interval,
954                                        GSourceFunc    func,
955                                        gpointer       data,
956                                        GDestroyNotify notify)
957 {
958   ClutterThreadsDispatch *dispatch;
959
960   g_return_val_if_fail (func != NULL, 0);
961
962   dispatch = g_slice_new (ClutterThreadsDispatch);
963   dispatch->func = func;
964   dispatch->data = data;
965   dispatch->notify = notify;
966
967   return clutter_frame_source_add_full (priority,
968                                         interval,
969                                         clutter_threads_dispatch, dispatch,
970                                         clutter_threads_dispatch_free);
971 }
972
973 /**
974  * clutter_threads_add_frame_source:
975  * @interval: the time between calls to the function, in milliseconds
976  * @func: function to call
977  * @data: data to pass to the function
978  *
979  * Simple wrapper around clutter_threads_add_frame_source_full().
980  *
981  * Return value: the ID (greater than 0) of the event source.
982  *
983  * Since: 0.8
984  */
985 guint
986 clutter_threads_add_frame_source (guint       interval,
987                                   GSourceFunc func,
988                                   gpointer    data)
989 {
990   g_return_val_if_fail (func != NULL, 0);
991
992   return clutter_threads_add_frame_source_full (G_PRIORITY_DEFAULT,
993                                                 interval,
994                                                 func, data,
995                                                 NULL);
996 }
997
998 /**
999  * clutter_threads_enter:
1000  *
1001  * Locks the Clutter thread lock.
1002  *
1003  * Since: 0.4
1004  */
1005 void
1006 clutter_threads_enter (void)
1007 {
1008   if (clutter_threads_lock)
1009     (* clutter_threads_lock) ();
1010 }
1011
1012 /**
1013  * clutter_threads_leave:
1014  *
1015  * Unlocks the Clutter thread lock.
1016  *
1017  * Since: 0.4
1018  */
1019 void
1020 clutter_threads_leave (void)
1021 {
1022   if (clutter_threads_unlock)
1023     (* clutter_threads_unlock) ();
1024 }
1025
1026
1027 /**
1028  * clutter_get_debug_enabled:
1029  *
1030  * Check if clutter has debugging turned on.
1031  *
1032  * Return value: TRUE if debugging is turned on, FALSE otherwise.
1033  */
1034 gboolean
1035 clutter_get_debug_enabled (void)
1036 {
1037 #ifdef CLUTTER_ENABLE_DEBUG
1038   return clutter_debug_flags != 0;
1039 #else
1040   return FALSE;
1041 #endif
1042 }
1043
1044 ClutterMainContext *
1045 clutter_context_get_default (void)
1046 {
1047   if (G_UNLIKELY(!ClutterCntx))
1048     {
1049       ClutterMainContext *ctx;
1050
1051       ClutterCntx = ctx = g_new0 (ClutterMainContext, 1);
1052       ctx->backend = g_object_new (_clutter_backend_impl_get_type (), NULL);
1053
1054       ctx->is_initialized = FALSE;
1055       ctx->motion_events_per_actor = TRUE;
1056
1057 #ifdef CLUTTER_ENABLE_DEBUG
1058       ctx->timer          =  g_timer_new ();
1059       g_timer_start (ctx->timer);
1060 #endif
1061     }
1062
1063   return ClutterCntx;
1064 }
1065
1066 /**
1067  * clutter_get_timestamp:
1068  *
1069  * Returns the approximate number of microseconds passed since clutter was
1070  * intialised.
1071  *
1072  * Return value: Number of microseconds since clutter_init() was called.
1073  */
1074 gulong
1075 clutter_get_timestamp (void)
1076 {
1077 #ifdef CLUTTER_ENABLE_DEBUG
1078   ClutterMainContext *ctx;
1079   gdouble seconds;
1080
1081   ctx = clutter_context_get_default ();
1082
1083   /* FIXME: may need a custom timer for embedded setups */
1084   seconds = g_timer_elapsed (ctx->timer, NULL);
1085
1086   return (gulong)(seconds / 1.0e-6);
1087 #else
1088   return 0;
1089 #endif
1090 }
1091
1092 static gboolean
1093 clutter_arg_direction_cb (const char *key,
1094                           const char *value,
1095                           gpointer    user_data)
1096 {
1097   clutter_text_direction =
1098     (strcmp (value, "rtl") == 0) ? PANGO_DIRECTION_RTL
1099                                  : PANGO_DIRECTION_LTR;
1100
1101   return TRUE;
1102 }
1103
1104 #ifdef CLUTTER_ENABLE_DEBUG
1105 static gboolean
1106 clutter_arg_debug_cb (const char *key,
1107                       const char *value,
1108                       gpointer    user_data)
1109 {
1110   clutter_debug_flags |=
1111     g_parse_debug_string (value,
1112                           clutter_debug_keys,
1113                           G_N_ELEMENTS (clutter_debug_keys));
1114   return TRUE;
1115 }
1116
1117 static gboolean
1118 clutter_arg_no_debug_cb (const char *key,
1119                          const char *value,
1120                          gpointer    user_data)
1121 {
1122   clutter_debug_flags &=
1123     ~g_parse_debug_string (value,
1124                            clutter_debug_keys,
1125                            G_N_ELEMENTS (clutter_debug_keys));
1126   return TRUE;
1127 }
1128 #endif /* CLUTTER_ENABLE_DEBUG */
1129
1130 GQuark
1131 clutter_init_error_quark (void)
1132 {
1133   return g_quark_from_static_string ("clutter-init-error-quark");
1134 }
1135
1136 static ClutterInitError
1137 clutter_init_real (GError **error)
1138 {
1139   ClutterMainContext *ctx;
1140   ClutterActor *stage;
1141   gdouble resolution;
1142   ClutterBackend *backend;
1143
1144   /* Note, creates backend if not already existing, though parse args will
1145    * have likely created it
1146    */
1147   ctx = clutter_context_get_default ();
1148   backend = ctx->backend;
1149
1150   if (!ctx->options_parsed)
1151     {
1152       g_set_error (error, CLUTTER_INIT_ERROR,
1153                    CLUTTER_INIT_ERROR_INTERNAL,
1154                    "When using clutter_get_option_group_without_init() "
1155                    "you must parse options before calling clutter_init()");
1156
1157       return CLUTTER_INIT_ERROR_INTERNAL;
1158     }
1159
1160   /*
1161    * Call backend post parse hooks.
1162    */
1163   if (!_clutter_backend_post_parse (backend, error))
1164     return CLUTTER_INIT_ERROR_BACKEND;
1165
1166   /* Stage will give us a GL Context etc */
1167   stage = clutter_stage_get_default ();
1168   if (!stage)
1169     {
1170       if (error)
1171         g_set_error (error, CLUTTER_INIT_ERROR,
1172                      CLUTTER_INIT_ERROR_INTERNAL,
1173                      "Unable to create the default stage");
1174       else
1175         g_critical ("Unable to create the default stage");
1176
1177       return CLUTTER_INIT_ERROR_INTERNAL;
1178     }
1179
1180   clutter_actor_realize (stage);
1181
1182   if (!CLUTTER_ACTOR_IS_REALIZED (stage))
1183     {
1184       if (error)
1185         g_set_error (error, CLUTTER_INIT_ERROR,
1186                      CLUTTER_INIT_ERROR_INTERNAL,
1187                      "Unable to realize the default stage");
1188       else
1189         g_critical ("Unable to realize the default stage");
1190
1191       return CLUTTER_INIT_ERROR_INTERNAL;
1192     }
1193
1194   /* Now we can safely assume we have a valid GL context and can
1195    * start issueing cogl commands
1196   */
1197
1198   /*
1199    * Resolution requires display to be open, so can only be queried after
1200    * the post_parse hooks run.
1201    *
1202    * NB: cogl_pango requires a Cogl context.
1203    */
1204   ctx->font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new ());
1205
1206   resolution = clutter_backend_get_resolution (ctx->backend);
1207   cogl_pango_font_map_set_resolution (ctx->font_map, resolution);
1208   cogl_pango_font_map_set_use_mipmapping (ctx->font_map, TRUE);
1209
1210   clutter_text_direction = clutter_get_text_direction ();
1211
1212
1213   /* Figure out framebuffer masks used for pick */
1214   cogl_get_bitmasks (&ctx->fb_r_mask, &ctx->fb_g_mask, &ctx->fb_b_mask, NULL);
1215
1216   ctx->fb_r_mask_used = ctx->fb_r_mask;
1217   ctx->fb_g_mask_used = ctx->fb_g_mask;
1218   ctx->fb_b_mask_used = ctx->fb_b_mask;
1219
1220 #ifndef HAVE_CLUTTER_FRUITY
1221   /* We always do fuzzy picking for the fruity backend */
1222   if (g_getenv ("CLUTTER_FUZZY_PICK") != NULL)
1223 #endif
1224     {
1225       ctx->fb_r_mask_used--;
1226       ctx->fb_g_mask_used--;
1227       ctx->fb_b_mask_used--;
1228     }
1229
1230   /* Initiate event collection */
1231   _clutter_backend_init_events (ctx->backend);
1232
1233   /* finally features - will call to backend and cogl */
1234   _clutter_feature_init ();
1235
1236   clutter_stage_set_title (CLUTTER_STAGE (stage), g_get_prgname ());
1237
1238   clutter_is_initialized = TRUE;
1239   ctx->is_initialized = TRUE;
1240
1241   return CLUTTER_INIT_SUCCESS;
1242 }
1243
1244 static GOptionEntry clutter_args[] = {
1245   { "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
1246     N_("Show frames per second"), NULL },
1247   { "clutter-default-fps", 0, 0, G_OPTION_ARG_INT, &clutter_default_fps,
1248     N_("Default frame rate"), "FPS" },
1249   { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings,
1250     N_("Make all warnings fatal"), NULL },
1251   { "clutter-text-direction", 0, 0, G_OPTION_ARG_CALLBACK,
1252     clutter_arg_direction_cb,
1253     N_("Direction for the text"), "DIRECTION" },
1254 #ifdef CLUTTER_ENABLE_DEBUG
1255   { "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
1256     N_("Clutter debugging flags to set"), "FLAGS" },
1257   { "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb,
1258     N_("Clutter debugging flags to unset"), "FLAGS" },
1259 #endif /* CLUTTER_ENABLE_DEBUG */
1260   { NULL, },
1261 };
1262
1263 /* pre_parse_hook: initialise variables depending on environment
1264  * variables; these variables might be overridden by the command
1265  * line arguments that are going to be parsed after.
1266  */
1267 static gboolean
1268 pre_parse_hook (GOptionContext  *context,
1269                 GOptionGroup    *group,
1270                 gpointer         data,
1271                 GError         **error)
1272 {
1273   ClutterMainContext *clutter_context;
1274   ClutterBackend *backend;
1275   const char *env_string;
1276
1277   if (clutter_is_initialized)
1278     return TRUE;
1279
1280   if (setlocale (LC_ALL, "") == NULL)
1281     g_warning ("Locale not supported by C library.\n"
1282                "Using the fallback 'C' locale.");
1283
1284   clutter_context = clutter_context_get_default ();
1285
1286   clutter_context->id_pool = clutter_id_pool_new (256);
1287
1288   backend = clutter_context->backend;
1289   g_assert (CLUTTER_IS_BACKEND (backend));
1290
1291 #ifdef CLUTTER_ENABLE_DEBUG
1292   env_string = g_getenv ("CLUTTER_DEBUG");
1293   if (env_string != NULL)
1294     {
1295       clutter_debug_flags =
1296         g_parse_debug_string (env_string,
1297                               clutter_debug_keys,
1298                               G_N_ELEMENTS (clutter_debug_keys));
1299       env_string = NULL;
1300     }
1301 #endif /* CLUTTER_ENABLE_DEBUG */
1302
1303   env_string = g_getenv ("CLUTTER_SHOW_FPS");
1304   if (env_string)
1305     clutter_show_fps = TRUE;
1306
1307   env_string = g_getenv ("CLUTTER_DEFAULT_FPS");
1308   if (env_string)
1309     {
1310       gint default_fps = g_ascii_strtoll (env_string, NULL, 10);
1311
1312       clutter_default_fps = CLAMP (default_fps, 1, 1000);
1313     }
1314
1315   return _clutter_backend_pre_parse (backend, error);
1316 }
1317
1318 /* post_parse_hook: initialise the context and data structures
1319  * and opens the X display
1320  */
1321 static gboolean
1322 post_parse_hook (GOptionContext  *context,
1323                  GOptionGroup    *group,
1324                  gpointer         data,
1325                  GError         **error)
1326 {
1327   ClutterMainContext *clutter_context;
1328   ClutterBackend *backend;
1329
1330   if (clutter_is_initialized)
1331     return TRUE;
1332
1333   clutter_context = clutter_context_get_default ();
1334   backend = clutter_context->backend;
1335   g_assert (CLUTTER_IS_BACKEND (backend));
1336
1337   if (clutter_fatal_warnings)
1338     {
1339       GLogLevelFlags fatal_mask;
1340
1341       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
1342       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
1343       g_log_set_always_fatal (fatal_mask);
1344     }
1345
1346   clutter_context->frame_rate = clutter_default_fps;
1347   clutter_context->options_parsed = TRUE;
1348
1349   /*
1350    * If not asked to defer display setup, call clutter_init_real(),
1351    * which in turn calls the backend post parse hooks.
1352    */
1353   if (!clutter_context->defer_display_setup)
1354     return clutter_init_real (error);
1355
1356   return TRUE;
1357 }
1358
1359 /**
1360  * clutter_get_option_group:
1361  *
1362  * Returns a #GOptionGroup for the command line arguments recognized
1363  * by Clutter. You should add this group to your #GOptionContext with
1364  * g_option_context_add_group(), if you are using g_option_context_parse()
1365  * to parse your commandline arguments.
1366  *
1367  * Calling g_option_context_parse() with Clutter's #GOptionGroup will result
1368  * in Clutter's initialization. That is, the following code:
1369  *
1370  * |[
1371  *   g_option_context_set_main_group (context, clutter_get_option_group ());
1372  *   res = g_option_context_parse (context, &amp;argc, &amp;argc, NULL);
1373  * ]|
1374  *
1375  * is functionally equivalent to:
1376  *
1377  * |[
1378  *   clutter_init (&amp;argc, &amp;argv);
1379  * ]|
1380  *
1381  * After g_option_context_parse() on a #GOptionContext containing the
1382  * Clutter #GOptionGroup has returned %TRUE, Clutter is guaranteed to be
1383  * initialized.
1384  *
1385  * Return value: a #GOptionGroup for the commandline arguments
1386  *   recognized by Clutter
1387  *
1388  * Since: 0.2
1389  */
1390 GOptionGroup *
1391 clutter_get_option_group (void)
1392 {
1393   ClutterMainContext *context;
1394   GOptionGroup *group;
1395
1396   clutter_base_init ();
1397
1398   context = clutter_context_get_default ();
1399
1400   group = g_option_group_new ("clutter",
1401                               _("Clutter Options"),
1402                               _("Show Clutter Options"),
1403                               NULL,
1404                               NULL);
1405
1406   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
1407   g_option_group_add_entries (group, clutter_args);
1408   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
1409
1410   /* add backend-specific options */
1411   _clutter_backend_add_options (context->backend, group);
1412
1413   return group;
1414 }
1415
1416 /**
1417  * clutter_get_option_group_without_init:
1418  *
1419  * Returns a #GOptionGroup for the command line arguments recognized
1420  * by Clutter. You should add this group to your #GOptionContext with
1421  * g_option_context_add_group(), if you are using g_option_context_parse()
1422  * to parse your commandline arguments. Unlike clutter_get_option_group(),
1423  * calling g_option_context_parse() with the #GOptionGroup returned by this
1424  * function requires a subsequent explicit call to clutter_init(); use this
1425  * function when needing to set foreign display connection with
1426  * clutter_x11_set_display(), or with gtk_clutter_init().
1427  *
1428  * Return value: a #GOptionGroup for the commandline arguments
1429  *   recognized by Clutter
1430  *
1431  * Since: 0.8.2
1432  */
1433 GOptionGroup *
1434 clutter_get_option_group_without_init (void)
1435 {
1436   ClutterMainContext *context;
1437   GOptionGroup *group;
1438
1439   clutter_base_init ();
1440
1441   context = clutter_context_get_default ();
1442   context->defer_display_setup = TRUE;
1443
1444   group = clutter_get_option_group ();
1445
1446   return group;
1447 }
1448
1449 /**
1450  * clutter_init_with_args:
1451  * @argc: a pointer to the number of command line arguments
1452  * @argv: a pointer to the array of command line arguments
1453  * @parameter_string: a string which is displayed in the
1454  *   first line of <option>--help</option> output, after
1455  *   <literal><replaceable>programname</replaceable> [OPTION...]</literal>
1456  * @entries: a %NULL terminated array of #GOptionEntry<!-- -->s
1457  *   describing the options of your program
1458  * @translation_domain: a translation domain to use for translating
1459  *   the <option>--help</option> output for the options in @entries
1460  *   with gettext(), or %NULL
1461  * @error: a return location for a #GError
1462  *
1463  * This function does the same work as clutter_init(). Additionally,
1464  * it allows you to add your own command line options, and it
1465  * automatically generates nicely formatted <option>--help</option>
1466  * output. Note that your program will be terminated after writing
1467  * out the help output. Also note that, in case of error, the
1468  * error message will be placed inside @error instead of being
1469  * printed on the display.
1470  *
1471  * Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully
1472  *   initialised, or other values or #ClutterInitError in case of
1473  *   error.
1474  *
1475  * Since: 0.2
1476  */
1477 ClutterInitError
1478 clutter_init_with_args (int            *argc,
1479                         char         ***argv,
1480                         const char     *parameter_string,
1481                         GOptionEntry   *entries,
1482                         const char     *translation_domain,
1483                         GError        **error)
1484 {
1485   GOptionContext *context;
1486   GOptionGroup *group;
1487   gboolean res;
1488   ClutterMainContext *ctx;
1489
1490   if (clutter_is_initialized)
1491     return CLUTTER_INIT_SUCCESS;
1492
1493   clutter_base_init ();
1494
1495   ctx = clutter_context_get_default ();
1496
1497   if (!ctx->defer_display_setup)
1498     {
1499       if (argc && *argc > 0 && *argv)
1500         g_set_prgname ((*argv)[0]);
1501
1502       group   = clutter_get_option_group ();
1503       context = g_option_context_new (parameter_string);
1504
1505       g_option_context_add_group (context, group);
1506
1507       if (entries)
1508         g_option_context_add_main_entries (context, entries, translation_domain);
1509
1510       res = g_option_context_parse (context, argc, argv, error);
1511       g_option_context_free (context);
1512
1513       /* if res is FALSE, the error is filled for
1514        * us by g_option_context_parse()
1515        */
1516       if (!res)
1517         {
1518           /* if there has been an error in the initialization, the
1519            * error id will be preserved inside the GError code
1520            */
1521           if (error && *error)
1522             return (*error)->code;
1523           else
1524             return CLUTTER_INIT_ERROR_INTERNAL;
1525         }
1526
1527       return CLUTTER_INIT_SUCCESS;
1528     }
1529   else
1530     return clutter_init_real (error);
1531 }
1532
1533 static gboolean
1534 clutter_parse_args (int    *argc,
1535                     char ***argv)
1536 {
1537   GOptionContext *option_context;
1538   GOptionGroup   *clutter_group;
1539   GError         *error = NULL;
1540   gboolean        ret = TRUE;
1541
1542   if (clutter_is_initialized)
1543     return TRUE;
1544
1545   option_context = g_option_context_new (NULL);
1546   g_option_context_set_ignore_unknown_options (option_context, TRUE);
1547   g_option_context_set_help_enabled (option_context, FALSE);
1548
1549   /* Initiate any command line options from the backend */
1550
1551   clutter_group = clutter_get_option_group ();
1552   g_option_context_set_main_group (option_context, clutter_group);
1553
1554   if (!g_option_context_parse (option_context, argc, argv, &error))
1555     {
1556       if (error)
1557         {
1558           g_warning ("%s", error->message);
1559           g_error_free (error);
1560         }
1561
1562       ret = FALSE;
1563     }
1564
1565   g_option_context_free (option_context);
1566
1567   return ret;
1568 }
1569
1570 /**
1571  * clutter_init:
1572  * @argc: The number of arguments in @argv
1573  * @argv: A pointer to an array of arguments.
1574  *
1575  * It will initialise everything needed to operate with Clutter and
1576  * parses some standard command line options. @argc and @argv are
1577  * adjusted accordingly so your own code will never see those standard
1578  * arguments.
1579  *
1580  * Return value: 1 on success, < 0 on failure.
1581  */
1582 ClutterInitError
1583 clutter_init (int    *argc,
1584               char ***argv)
1585 {
1586   ClutterMainContext *ctx;
1587   GError *error = NULL;
1588
1589   if (clutter_is_initialized)
1590     return CLUTTER_INIT_SUCCESS;
1591
1592   clutter_base_init ();
1593
1594   ctx = clutter_context_get_default ();
1595
1596   if (!ctx->defer_display_setup)
1597     {
1598       if (argc && *argc > 0 && *argv)
1599         g_set_prgname ((*argv)[0]);
1600
1601       /* parse_args will trigger backend creation and things like
1602        * DISPLAY connection etc.
1603        */
1604       if (clutter_parse_args (argc, argv) == FALSE)
1605         {
1606           CLUTTER_NOTE (MISC, "failed to parse arguments.");
1607           return CLUTTER_INIT_ERROR_INTERNAL;
1608         }
1609
1610       return CLUTTER_INIT_SUCCESS;
1611     }
1612   else
1613     return clutter_init_real (&error);
1614 }
1615
1616 gboolean
1617 _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
1618                                       GValue                *return_accu,
1619                                       const GValue          *handler_return,
1620                                       gpointer               dummy)
1621 {
1622   gboolean continue_emission;
1623   gboolean signal_handled;
1624
1625   signal_handled = g_value_get_boolean (handler_return);
1626   g_value_set_boolean (return_accu, signal_handled);
1627   continue_emission = !signal_handled;
1628
1629   return continue_emission;
1630 }
1631
1632 static void
1633 event_click_count_generate (ClutterEvent *event)
1634 {
1635   /* multiple button click detection */
1636   static gint    click_count            = 0;
1637   static gint    previous_x             = -1;
1638   static gint    previous_y             = -1;
1639   static guint32 previous_time          = 0;
1640   static gint    previous_button_number = -1;
1641
1642   ClutterBackend *backend;
1643   guint           double_click_time;
1644   guint           double_click_distance;
1645
1646   backend = clutter_context_get_default ()->backend;
1647   double_click_distance = clutter_backend_get_double_click_distance (backend);
1648   double_click_time = clutter_backend_get_double_click_time (backend);
1649
1650   if (event->button.device != NULL)
1651     {
1652       click_count = event->button.device->click_count;
1653       previous_x = event->button.device->previous_x;
1654       previous_y = event->button.device->previous_y;
1655       previous_time = event->button.device->previous_time;
1656       previous_button_number = event->button.device->previous_button_number;
1657     }
1658
1659   switch (event->type)
1660     {
1661       case CLUTTER_BUTTON_PRESS:
1662       case CLUTTER_SCROLL:
1663         /* check if we are in time and within distance to increment an
1664          * existing click count
1665          */
1666         if (event->button.time < previous_time + double_click_time &&
1667             (ABS (event->button.x - previous_x) <= double_click_distance) &&
1668             (ABS (event->button.y - previous_y) <= double_click_distance)
1669             && event->button.button == previous_button_number)
1670           {
1671             click_count ++;
1672           }
1673         else /* start a new click count*/
1674           {
1675             click_count=1;
1676             previous_button_number = event->button.button;
1677           }
1678
1679         /* store time and position for this click for comparison with
1680          * next event
1681          */
1682         previous_time = event->button.time;
1683         previous_x    = event->button.x;
1684         previous_y    = event->button.y;
1685
1686         /* fallthrough */
1687       case CLUTTER_BUTTON_RELEASE:
1688         event->button.click_count=click_count;
1689         break;
1690       default:
1691         g_assert (NULL);
1692     }
1693
1694   if (event->button.device != NULL)
1695     {
1696       event->button.device->click_count = click_count;
1697       event->button.device->previous_x = previous_x;
1698       event->button.device->previous_y = previous_y;
1699       event->button.device->previous_time = previous_time;
1700       event->button.device->previous_button_number = previous_button_number;
1701     }
1702 }
1703
1704
1705 static inline void
1706 emit_event (ClutterEvent *event,
1707             gboolean      is_key_event)
1708 {
1709 #define MAX_EVENT_DEPTH 512
1710
1711   static ClutterActor **event_tree = NULL;
1712   static gboolean       lock = FALSE;
1713
1714   ClutterActor         *actor;
1715   gint                  i = 0, n_tree_events = 0;
1716
1717   if (!event->any.source)
1718     {
1719       g_warning ("No event source set, discarding event");
1720       return;
1721     }
1722
1723   /* reentrancy check */
1724   if (lock != FALSE)
1725     return;
1726
1727   lock = TRUE;
1728
1729   /* Sorry Mr Bassi. */
1730   if (G_UNLIKELY (event_tree == NULL))
1731     event_tree = g_new0 (ClutterActor *, MAX_EVENT_DEPTH);
1732
1733   actor = event->any.source;
1734
1735   /* Build 'tree' of emitters for the event */
1736   while (actor && n_tree_events < MAX_EVENT_DEPTH)
1737     {
1738       ClutterActor *parent;
1739
1740       parent = clutter_actor_get_parent (actor);
1741
1742       if (clutter_actor_get_reactive (actor) ||
1743           parent == NULL ||         /* stage gets all events */
1744           is_key_event)             /* keyboard events are always emitted */
1745         {
1746           event_tree[n_tree_events++] = g_object_ref (actor);
1747         }
1748
1749       actor = parent;
1750     }
1751
1752   /* Capture */
1753   for (i = n_tree_events-1; i >= 0; i--)
1754     if (clutter_actor_event (event_tree[i], event, TRUE))
1755       goto done;
1756
1757   /* Bubble */
1758   for (i = 0; i < n_tree_events; i++)
1759     if (clutter_actor_event (event_tree[i], event, FALSE))
1760       goto done;
1761
1762 done:
1763
1764   for (i = 0; i < n_tree_events; i++)
1765     g_object_unref (event_tree[i]);
1766
1767   lock = FALSE;
1768
1769 #undef MAX_EVENT_DEPTH
1770 }
1771
1772 /*
1773  * Emits a pointer event after having prepared the event for delivery (setting
1774  * source, computing click_count, generating enter/leave etc.).
1775  */
1776
1777 static inline void
1778 emit_pointer_event (ClutterEvent       *event,
1779                     ClutterInputDevice *device)
1780 {
1781   /* Using the global variable directly, since it has to be initialized
1782    * at this point
1783    */
1784   ClutterMainContext *context = ClutterCntx;
1785
1786   if (G_UNLIKELY (context->pointer_grab_actor != NULL &&
1787                   device == NULL))
1788     {
1789       /* global grab */
1790       clutter_actor_event (context->pointer_grab_actor, event, FALSE);
1791     }
1792   else if (G_UNLIKELY (device != NULL &&
1793                        device->pointer_grab_actor != NULL))
1794     {
1795       /* per device grab */
1796       clutter_actor_event (device->pointer_grab_actor, event, FALSE);
1797     }
1798   else
1799     {
1800       /* no grab, time to capture and bubble */
1801       emit_event (event, FALSE);
1802     }
1803 }
1804
1805 static inline void
1806 emit_keyboard_event (ClutterEvent *event)
1807 {
1808   ClutterMainContext *context = ClutterCntx;
1809
1810   if (G_UNLIKELY (context->keyboard_grab_actor != NULL))
1811     clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
1812   else
1813     emit_event (event, TRUE);
1814 }
1815
1816 static void
1817 unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
1818 {
1819   ClutterMainContext *context = ClutterCntx;
1820
1821   if (dev == NULL)
1822     context->motion_last_actor = NULL;
1823   else
1824     dev->motion_last_actor = NULL;
1825 }
1826
1827 static ClutterInputDevice * clutter_event_get_device (ClutterEvent *event);
1828
1829 /* This function should perhaps be public and in clutter-event.c ?
1830  */
1831 static ClutterInputDevice *
1832 clutter_event_get_device (ClutterEvent *event)
1833 {
1834   g_return_val_if_fail (event != NULL, NULL);
1835
1836   switch (event->type)
1837     {
1838     case CLUTTER_NOTHING:
1839     case CLUTTER_STAGE_STATE:
1840     case CLUTTER_DESTROY_NOTIFY:
1841     case CLUTTER_CLIENT_MESSAGE:
1842     case CLUTTER_DELETE:
1843     case CLUTTER_ENTER:
1844     case CLUTTER_LEAVE:
1845       return NULL;
1846       break;
1847     case CLUTTER_BUTTON_PRESS:
1848     case CLUTTER_BUTTON_RELEASE:
1849       return event->button.device;
1850     case CLUTTER_MOTION:
1851       return event->motion.device;
1852     case CLUTTER_SCROLL:
1853       return event->scroll.device;
1854       break;
1855     case CLUTTER_KEY_PRESS:
1856     case CLUTTER_KEY_RELEASE:
1857       break;
1858     }
1859   return NULL;
1860 }
1861
1862 static inline void
1863 generate_enter_leave_events (ClutterEvent *event)
1864 {
1865   ClutterMainContext *context              = ClutterCntx;
1866   ClutterActor       *motion_current_actor = event->motion.source;
1867   ClutterActor       *last_actor           = context->motion_last_actor;
1868   ClutterInputDevice *device               = clutter_event_get_device (event);
1869
1870   if (device != NULL)
1871     last_actor = device->motion_last_actor;
1872
1873   if (last_actor != motion_current_actor)
1874     {
1875       if (motion_current_actor)
1876         {
1877           gint         x, y;
1878           ClutterEvent cev;
1879
1880           cev.crossing.device  = device;
1881           clutter_event_get_coords (event, &x, &y);
1882
1883           if (context->motion_last_actor)
1884             {
1885               cev.crossing.type    = CLUTTER_LEAVE;
1886               cev.crossing.time    = event->any.time;
1887               cev.crossing.flags   = 0;
1888               cev.crossing.x       = x;
1889               cev.crossing.y       = y;
1890               cev.crossing.source  = last_actor;
1891               cev.crossing.stage   = event->any.stage;
1892               cev.crossing.related = motion_current_actor;
1893
1894               emit_pointer_event (&cev, device);
1895             }
1896
1897           cev.crossing.type    = CLUTTER_ENTER;
1898           cev.crossing.time    = event->any.time;
1899           cev.crossing.flags   = 0;
1900           cev.crossing.x       = x;
1901           cev.crossing.y       = y;
1902           cev.crossing.source  = motion_current_actor;
1903           cev.crossing.stage   = event->any.stage;
1904
1905           if (context->motion_last_actor)
1906             cev.crossing.related = last_actor;
1907           else
1908             cev.crossing.related = NULL;
1909
1910           emit_pointer_event (&cev, device);
1911         }
1912     }
1913
1914   if (last_actor && last_actor != motion_current_actor)
1915     {
1916       g_signal_handlers_disconnect_by_func
1917                        (last_actor,
1918                         G_CALLBACK (unset_motion_last_actor),
1919                         device);
1920     }
1921
1922   if (motion_current_actor && last_actor != motion_current_actor)
1923     {
1924       g_signal_connect (motion_current_actor, "destroy",
1925                         G_CALLBACK (unset_motion_last_actor),
1926                         device);
1927     }
1928
1929   if (device != NULL)
1930     device->motion_last_actor = motion_current_actor;
1931   else
1932     context->motion_last_actor = motion_current_actor;
1933 }
1934
1935 /**
1936  * clutter_do_event
1937  * @event: a #ClutterEvent.
1938  *
1939  * Processes an event. This function should never be called by applications.
1940  *
1941  * Since: 0.4
1942  */
1943 void
1944 clutter_do_event (ClutterEvent *event)
1945 {
1946   /* FIXME: This should probably be clutter_cook_event() - it would
1947    * take a raw event from the backend and 'cook' it so its more tasty.
1948    *
1949   */
1950   ClutterMainContext  *context;
1951   ClutterBackend      *backend;
1952   ClutterActor        *stage;
1953   ClutterInputDevice  *device = NULL;
1954   static gint32        motion_last_time = 0L;
1955   gint32               local_motion_time;
1956
1957   context = clutter_context_get_default ();
1958   backend = context->backend;
1959   stage   = CLUTTER_ACTOR(event->any.stage);
1960
1961   if (!stage)
1962     return;
1963
1964   CLUTTER_TIMESTAMP (EVENT, "Event received");
1965
1966   switch (event->type)
1967     {
1968       case CLUTTER_NOTHING:
1969         event->any.source = stage;
1970         break;
1971
1972       case CLUTTER_ENTER:
1973       case CLUTTER_LEAVE:
1974         emit_pointer_event (event, event->crossing.device);
1975         break;
1976
1977       case CLUTTER_DESTROY_NOTIFY:
1978       case CLUTTER_DELETE:
1979         event->any.source = stage;
1980         /* the stage did not handle the event, so we just quit */
1981         if (!clutter_stage_event (CLUTTER_STAGE (stage), event))
1982           {
1983             if (stage == clutter_stage_get_default())
1984               clutter_main_quit ();
1985             else
1986               clutter_actor_destroy (stage);
1987           }
1988
1989         break;
1990
1991       case CLUTTER_KEY_PRESS:
1992       case CLUTTER_KEY_RELEASE:
1993         {
1994           ClutterActor *actor = NULL;
1995
1996           /* check that we're not a synthetic event with source set */
1997           if (event->any.source == NULL)
1998             {
1999               actor = clutter_stage_get_key_focus (CLUTTER_STAGE (stage));
2000               event->any.source = actor;
2001               if (G_UNLIKELY (actor == NULL))
2002                 {
2003                   g_warning ("No key focus set, discarding");
2004                   return;
2005                 }
2006             }
2007
2008           emit_keyboard_event (event);
2009         }
2010         break;
2011
2012       case CLUTTER_MOTION:
2013         device = event->motion.device;
2014
2015         if (device)
2016           local_motion_time = device->motion_last_time;
2017         else
2018           local_motion_time = motion_last_time;
2019
2020         /* avoid rate throttling for synthetic motion events or if
2021          * the per-actor events are disabled
2022          */
2023         if (!(event->any.flags & CLUTTER_EVENT_FLAG_SYNTHETIC) ||
2024             !context->motion_events_per_actor)
2025           {
2026             gint32 frame_rate, delta;
2027
2028             /* avoid issuing too many motion events, which leads to many
2029              * redraws in pick mode (performance penalty)
2030              */
2031             frame_rate = clutter_get_motion_events_frequency ();
2032             delta = 1000 / frame_rate;
2033
2034             CLUTTER_NOTE (EVENT,
2035                   "skip motion event: %s (last:%d, delta:%d, time:%d)",
2036                   (event->any.time < (local_motion_time + delta) ? "yes" : "no"),
2037                   local_motion_time,
2038                   delta,
2039                   event->any.time);
2040
2041             /* we need to guard against roll-overs and the
2042              * case where the time is rolled backwards and
2043              * the backend is not ensuring a monotonic clock
2044              * for the events.
2045              *
2046              * see:
2047              *   http://bugzilla.openedhand.com/show_bug.cgi?id=1130
2048              */
2049             if (event->any.time >= local_motion_time &&
2050                 event->any.time < (local_motion_time + delta))
2051               break;
2052             else
2053               local_motion_time = event->any.time;
2054           }
2055
2056         if (device)
2057           device->motion_last_time = local_motion_time;
2058         else
2059           motion_last_time = local_motion_time;
2060
2061         /* Only stage gets motion events if clutter_set_motion_events is TRUE,
2062          * and the event is not a synthetic event with source set.
2063          */
2064         if (!context->motion_events_per_actor &&
2065             event->any.source == NULL)
2066           {
2067             /* Only stage gets motion events */
2068             event->any.source = stage;
2069
2070             /* global grabs */
2071             if (context->pointer_grab_actor != NULL)
2072               {
2073                 clutter_actor_event (context->pointer_grab_actor,
2074                                      event, FALSE);
2075                 break;
2076               }
2077             else if (device != NULL && device->pointer_grab_actor != NULL)
2078               {
2079                 clutter_actor_event (device->pointer_grab_actor,
2080                                      event, FALSE);
2081                 break;
2082               }
2083
2084             /* Trigger handlers on stage in both capture .. */
2085             if (!clutter_actor_event (stage, event, TRUE))
2086               {
2087                 /* and bubbling phase */
2088                 clutter_actor_event (stage, event, FALSE);
2089               }
2090             break;
2091           }
2092
2093         /* fallthrough */
2094
2095       case CLUTTER_BUTTON_PRESS:
2096       case CLUTTER_BUTTON_RELEASE:
2097       case CLUTTER_SCROLL:
2098         {
2099           ClutterActor *actor;
2100           gint          x,y;
2101
2102           clutter_event_get_coords (event, &x, &y);
2103
2104           /* Only do a pick to find the source if source is not already set
2105            * (as it could be in a synthetic event)
2106            */
2107           if (event->any.source == NULL)
2108             {
2109               /* Handle release off stage */
2110               if ((x >= clutter_actor_get_width (stage) ||
2111                    y >= clutter_actor_get_height (stage) ||
2112                    x < 0 || y < 0))
2113                 {
2114                   if (event->type == CLUTTER_BUTTON_RELEASE)
2115                     {
2116                       CLUTTER_NOTE (EVENT,
2117                                     "Release off stage received at %i, %i",
2118                                     x, y);
2119
2120                       event->button.source = stage;
2121                       emit_pointer_event (event, event->button.device);
2122                     }
2123                   break;
2124                 }
2125
2126               /* Map the event to a reactive actor */
2127               actor = _clutter_do_pick (CLUTTER_STAGE (stage),
2128                                         x, y,
2129                                         CLUTTER_PICK_REACTIVE);
2130
2131               event->any.source = actor;
2132               if (!actor)
2133                 break;
2134             }
2135           else
2136             {
2137               /* use the source already set in the synthetic event */
2138               actor = event->any.source;
2139             }
2140
2141
2142           /* FIXME: for an optimisation should check if there are
2143            * actually any reactive actors and avoid the pick all togeather
2144            * (signalling just the stage). Should be big help for gles.
2145            */
2146
2147           CLUTTER_NOTE (EVENT, "Reactive event received at %i, %i - actor: %p",
2148                         x, y, actor);
2149
2150           /* Create, enter/leave events if needed */
2151           generate_enter_leave_events (event);
2152
2153           if (event->type != CLUTTER_MOTION)
2154             {
2155               /* Generate click count */
2156               event_click_count_generate (event);
2157             }
2158
2159           if (device == NULL)
2160             {
2161               switch (event->type)
2162                 {
2163                   case CLUTTER_BUTTON_PRESS:
2164                   case CLUTTER_BUTTON_RELEASE:
2165                     device = event->button.device;
2166                     break;
2167                   case CLUTTER_SCROLL:
2168                     device = event->scroll.device;
2169                     break;
2170                   case CLUTTER_MOTION:
2171                     /* already handled in the MOTION case of the switch */
2172                   default:
2173                     break;
2174                 }
2175             }
2176
2177           emit_pointer_event (event, device);
2178           break;
2179         }
2180
2181       case CLUTTER_STAGE_STATE:
2182         /* fullscreen / focus - forward to stage */
2183         event->any.source = stage;
2184         clutter_stage_event (CLUTTER_STAGE (stage), event);
2185         break;
2186
2187       case CLUTTER_CLIENT_MESSAGE:
2188         break;
2189     }
2190 }
2191
2192 /**
2193  * clutter_get_actor_by_gid
2194  * @id: a #ClutterActor ID.
2195  *
2196  * Retrieves the #ClutterActor with @id.
2197  *
2198  * Return value: the actor with the passed id or %NULL. The returned
2199  *   actor does not have its reference count increased.
2200  *
2201  * Since: 0.6
2202  */
2203 ClutterActor*
2204 clutter_get_actor_by_gid (guint32 id)
2205 {
2206   ClutterMainContext *context;
2207
2208   context = clutter_context_get_default ();
2209
2210   g_return_val_if_fail (context != NULL, NULL);
2211
2212   return CLUTTER_ACTOR (clutter_id_pool_lookup (context->id_pool, id));
2213 }
2214
2215 void
2216 clutter_base_init (void)
2217 {
2218   static gboolean initialised = FALSE;
2219
2220   if (!initialised)
2221     {
2222       GType foo; /* Quiet gcc */
2223
2224       initialised = TRUE;
2225
2226       bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2227       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2228
2229       /* initialise GLib type system */
2230       g_type_init ();
2231
2232       /* CLUTTER_TYPE_ACTOR */
2233       foo = clutter_actor_get_type ();
2234     }
2235 }
2236
2237 /**
2238  * clutter_get_default_frame_rate:
2239  *
2240  * Retrieves the default frame rate used when creating #ClutterTimeline<!--
2241  * -->s.
2242  *
2243  * This value is also used to compute the default frequency of motion
2244  * events.
2245  *
2246  * Return value: the default frame rate
2247  *
2248  * Since: 0.6
2249  */
2250 guint
2251 clutter_get_default_frame_rate (void)
2252 {
2253   ClutterMainContext *context;
2254
2255   context = clutter_context_get_default ();
2256
2257   return context->frame_rate;
2258 }
2259
2260 /**
2261  * clutter_set_default_frame_rate:
2262  * @frames_per_sec: the new default frame rate
2263  *
2264  * Sets the default frame rate to be used when creating #ClutterTimeline<!--
2265  * -->s
2266  *
2267  * Since: 0.6
2268  */
2269 void
2270 clutter_set_default_frame_rate (guint frames_per_sec)
2271 {
2272   ClutterMainContext *context;
2273
2274   context = clutter_context_get_default ();
2275
2276   if (context->frame_rate != frames_per_sec)
2277     context->frame_rate = frames_per_sec;
2278 }
2279
2280
2281 static void
2282 on_pointer_grab_weak_notify (gpointer data,
2283                              GObject *where_the_object_was)
2284 {
2285   ClutterInputDevice *dev = (ClutterInputDevice *)data;
2286   ClutterMainContext *context;
2287
2288   context = clutter_context_get_default ();
2289
2290   if (dev)
2291     {
2292       dev->pointer_grab_actor = NULL;
2293       clutter_ungrab_pointer_for_device (dev->id);
2294     }
2295   else
2296     {
2297       context->pointer_grab_actor = NULL;
2298       clutter_ungrab_pointer ();
2299     }
2300 }
2301
2302 /**
2303  * clutter_grab_pointer:
2304  * @actor: a #ClutterActor
2305  *
2306  * Grabs pointer events, after the grab is done all pointer related events
2307  * (press, motion, release, enter, leave and scroll) are delivered to this
2308  * actor directly. The source set in the event will be the actor that would
2309  * have received the event if the pointer grab was not in effect.
2310  *
2311  * If you wish to grab all the pointer events for a specific input device,
2312  * you should use clutter_grab_pointer_for_device().
2313  *
2314  * Since: 0.6
2315  */
2316 void
2317 clutter_grab_pointer (ClutterActor *actor)
2318 {
2319   ClutterMainContext *context;
2320
2321   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2322
2323   context = clutter_context_get_default ();
2324
2325   if (context->pointer_grab_actor == actor)
2326     return;
2327
2328   if (context->pointer_grab_actor)
2329     {
2330       g_object_weak_unref (G_OBJECT (context->pointer_grab_actor),
2331                            on_pointer_grab_weak_notify,
2332                            NULL);
2333       context->pointer_grab_actor = NULL;
2334     }
2335
2336   if (actor)
2337     {
2338       context->pointer_grab_actor = actor;
2339
2340       g_object_weak_ref (G_OBJECT (actor),
2341                          on_pointer_grab_weak_notify,
2342                          NULL);
2343     }
2344 }
2345
2346 /**
2347  * clutter_grab_pointer_for_device:
2348  * @actor: a #ClutterActor
2349  * @id: a device id, or -1
2350  *
2351  * Grabs all the pointer events coming from the device @id for @actor.
2352  *
2353  * If @id is -1 then this function is equivalent to clutter_grab_pointer().
2354  *
2355  * Since: 0.8
2356  */
2357 void
2358 clutter_grab_pointer_for_device (ClutterActor *actor,
2359                                  gint          id)
2360 {
2361   ClutterInputDevice *dev;
2362
2363   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2364
2365   /* essentially a global grab */
2366   if (id == -1)
2367     {
2368       clutter_grab_pointer (actor);
2369       return;
2370     }
2371
2372   dev = clutter_get_input_device_for_id (id);
2373
2374   if (!dev)
2375     return;
2376
2377   if (dev->pointer_grab_actor == actor)
2378     return;
2379
2380   if (dev->pointer_grab_actor)
2381     {
2382       g_object_weak_unref (G_OBJECT (dev->pointer_grab_actor),
2383                           on_pointer_grab_weak_notify,
2384                           dev);
2385       dev->pointer_grab_actor = NULL;
2386     }
2387
2388   if (actor)
2389     {
2390       dev->pointer_grab_actor = actor;
2391
2392       g_object_weak_ref (G_OBJECT (actor),
2393                         on_pointer_grab_weak_notify,
2394                         dev);
2395     }
2396 }
2397
2398
2399 /**
2400  * clutter_ungrab_pointer:
2401  *
2402  * Removes an existing grab of the pointer.
2403  *
2404  * Since: 0.6
2405  */
2406 void
2407 clutter_ungrab_pointer (void)
2408 {
2409   clutter_grab_pointer (NULL);
2410 }
2411
2412 /**
2413  * clutter_ungrab_pointer_for_device:
2414  * @id: a device id
2415  *
2416  * Removes an existing grab of the pointer events for device @id.
2417  *
2418  * Since: 0.8
2419  */
2420 void
2421 clutter_ungrab_pointer_for_device (gint id)
2422 {
2423   clutter_grab_pointer_for_device (NULL, id);
2424 }
2425
2426
2427 /**
2428  * clutter_get_pointer_grab:
2429  *
2430  * Queries the current pointer grab of clutter.
2431  *
2432  * Return value: the actor currently holding the pointer grab, or NULL if there is no grab.
2433  *
2434  * Since: 0.6
2435  */
2436 ClutterActor *
2437 clutter_get_pointer_grab (void)
2438 {
2439   ClutterMainContext *context;
2440   context = clutter_context_get_default ();
2441
2442   return context->pointer_grab_actor;
2443 }
2444
2445
2446 static void
2447 on_keyboard_grab_weak_notify (gpointer data,
2448                               GObject *where_the_object_was)
2449 {
2450   ClutterMainContext *context;
2451
2452   context = clutter_context_get_default ();
2453   context->keyboard_grab_actor = NULL;
2454
2455   clutter_ungrab_keyboard ();
2456 }
2457
2458 /**
2459  * clutter_grab_keyboard:
2460  * @actor: a #ClutterActor
2461  *
2462  * Grabs keyboard events, after the grab is done keyboard events ("key-press-event"
2463  * and "key-release-event") are delivered to this actor directly. The source
2464  * set in the event will be the actor that would have received the event if the
2465  * keyboard grab was not in effect.
2466  *
2467  * Since: 0.6
2468  */
2469 void
2470 clutter_grab_keyboard (ClutterActor *actor)
2471 {
2472   ClutterMainContext *context;
2473
2474   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2475
2476   context = clutter_context_get_default ();
2477
2478   if (context->keyboard_grab_actor == actor)
2479     return;
2480
2481   if (context->keyboard_grab_actor)
2482     {
2483       g_object_weak_unref (G_OBJECT (context->keyboard_grab_actor),
2484                            on_keyboard_grab_weak_notify,
2485                            NULL);
2486       context->keyboard_grab_actor = NULL;
2487     }
2488
2489   if (actor)
2490     {
2491       context->keyboard_grab_actor = actor;
2492
2493       g_object_weak_ref (G_OBJECT (actor),
2494                          on_keyboard_grab_weak_notify,
2495                          NULL);
2496     }
2497 }
2498
2499 /**
2500  * clutter_ungrab_keyboard:
2501  *
2502  * Removes an existing grab of the keyboard.
2503  *
2504  * Since: 0.6
2505  */
2506 void
2507 clutter_ungrab_keyboard (void)
2508 {
2509   clutter_grab_keyboard (NULL);
2510 }
2511
2512 /**
2513  * clutter_get_keyboard_grab:
2514  *
2515  * Queries the current keyboard grab of clutter.
2516  *
2517  * Return value: the actor currently holding the keyboard grab, or NULL if there is no grab.
2518  *
2519  * Since: 0.6
2520  */
2521 ClutterActor *
2522 clutter_get_keyboard_grab (void)
2523 {
2524   ClutterMainContext *context;
2525   context = clutter_context_get_default ();
2526
2527   return context->keyboard_grab_actor;
2528 }
2529
2530 /**
2531  * clutter_get_motion_events_frequency:
2532  *
2533  * Retrieves the number of motion events per second that are delivered
2534  * to the stage.
2535  *
2536  * See clutter_set_motion_events_frequency().
2537  *
2538  * Return value: the number of motion events per second
2539  *
2540  * Since: 0.6
2541  */
2542 guint
2543 clutter_get_motion_events_frequency (void)
2544 {
2545   ClutterMainContext *context = clutter_context_get_default ();
2546
2547   if (G_LIKELY (context->motion_frequency == 0))
2548     {
2549       guint frequency;
2550
2551       frequency = clutter_default_fps / 4;
2552       frequency = CLAMP (frequency, 20, 45);
2553
2554       return frequency;
2555     }
2556   else
2557     return context->motion_frequency;
2558 }
2559
2560 /**
2561  * clutter_set_motion_events_frequency:
2562  * @frequency: the number of motion events per second, or 0 for the
2563  *   default value
2564  *
2565  * Sets the motion events frequency. Setting this to a non-zero value
2566  * will override the default setting, so it should be rarely used.
2567  *
2568  * Motion events are delivered from the default backend to the stage
2569  * and are used to generate the enter/leave events pair. This might lead
2570  * to a performance penalty due to the way the actors are identified.
2571  * Using this function is possible to reduce the frequency of the motion
2572  * events delivery to the stage.
2573  *
2574  * Since: 0.6
2575  */
2576 void
2577 clutter_set_motion_events_frequency (guint frequency)
2578 {
2579   ClutterMainContext *context = clutter_context_get_default ();
2580
2581   /* never allow the motion events to exceed the default frame rate */
2582   context->motion_frequency = CLAMP (frequency, 1, clutter_default_fps);
2583 }
2584
2585 /**
2586  * clutter_clear_glyph_cache:
2587  *
2588  * Clears the internal cache of glyphs used by the Pango
2589  * renderer. This will free up some memory and GL texture
2590  * resources. The cache will be automatically refilled as more text is
2591  * drawn.
2592  *
2593  * Since: 0.8
2594  */
2595 void
2596 clutter_clear_glyph_cache (void)
2597 {
2598   if (CLUTTER_CONTEXT ()->font_map)
2599     cogl_pango_font_map_clear_glyph_cache (CLUTTER_CONTEXT ()->font_map);
2600 }
2601
2602 /**
2603  * clutter_set_font_flags:
2604  * @flags: The new flags
2605  *
2606  * Sets the font quality options for subsequent text rendering
2607  * operations.
2608  *
2609  * Using mipmapped textures will improve the quality for scaled down
2610  * text but will use more texture memory.
2611  *
2612  * Enabling hinting improves text quality for static text but may
2613  * introduce some artifacts if the text is animated. Changing the
2614  * hinting flag will only effect newly created PangoLayouts. So
2615  * #ClutterText actors will not show the change until a property which
2616  * causes it to recreate the layout is also changed.
2617  *
2618  * Since: 1.0
2619  */
2620 void
2621 clutter_set_font_flags (ClutterFontFlags flags)
2622 {
2623   ClutterFontFlags old_flags, changed_flags;
2624
2625   if (CLUTTER_CONTEXT ()->font_map)
2626     cogl_pango_font_map_set_use_mipmapping (CLUTTER_CONTEXT ()->font_map,
2627                                             (flags
2628                                              & CLUTTER_FONT_MIPMAPPING) != 0);
2629
2630   old_flags = clutter_get_font_flags ();
2631
2632   if (CLUTTER_CONTEXT ()->user_font_options == NULL)
2633     CLUTTER_CONTEXT ()->user_font_options = cairo_font_options_create ();
2634
2635   /* Only set the font options that have actually changed so we don't
2636      override a detailed setting from the backend */
2637   changed_flags = old_flags ^ flags;
2638
2639   if ((changed_flags & CLUTTER_FONT_HINTING))
2640     cairo_font_options_set_hint_style (CLUTTER_CONTEXT ()->user_font_options,
2641                                        (flags & CLUTTER_FONT_HINTING)
2642                                        ? CAIRO_HINT_STYLE_FULL
2643                                        : CAIRO_HINT_STYLE_NONE);
2644
2645   if (CLUTTER_CONTEXT ()->pango_context)
2646     update_pango_context (CLUTTER_CONTEXT ()->backend,
2647                           CLUTTER_CONTEXT ()->pango_context);
2648 }
2649
2650 /**
2651  * clutter_get_font_flags:
2652  *
2653  * Gets the current font flags for rendering text. See
2654  * clutter_set_font_flags().
2655  *
2656  * Return value: The font flags
2657  *
2658  * Since: 1.0
2659  */
2660 ClutterFontFlags
2661 clutter_get_font_flags (void)
2662 {
2663   ClutterMainContext *ctxt = CLUTTER_CONTEXT ();
2664   CoglPangoFontMap *font_map = NULL;
2665   cairo_font_options_t *font_options;
2666   ClutterFontFlags flags = 0;
2667
2668   font_map = CLUTTER_CONTEXT ()->font_map;
2669
2670   if (G_LIKELY (font_map)
2671       && cogl_pango_font_map_get_use_mipmapping (font_map))
2672     flags |= CLUTTER_FONT_MIPMAPPING;
2673
2674   font_options = clutter_backend_get_font_options (ctxt->backend);
2675   font_options = cairo_font_options_copy (font_options);
2676
2677   if (ctxt->user_font_options)
2678     cairo_font_options_merge (font_options, ctxt->user_font_options);
2679
2680   if ((cairo_font_options_get_hint_style (font_options)
2681        != CAIRO_HINT_STYLE_DEFAULT)
2682       && (cairo_font_options_get_hint_style (font_options)
2683           != CAIRO_HINT_STYLE_NONE))
2684     flags |= CLUTTER_FONT_HINTING;
2685
2686   cairo_font_options_destroy (font_options);
2687
2688   return flags;
2689 }
2690
2691 /**
2692  * clutter_get_input_device_for_id:
2693  * @id: a device id
2694  *
2695  * Retrieves the #ClutterInputDevice from its id.
2696  *
2697  * Return value: a #ClutterInputDevice, or %NULL
2698  *
2699  * Since: 0.8
2700  */
2701 ClutterInputDevice *
2702 clutter_get_input_device_for_id (gint id)
2703 {
2704   GSList *item;
2705   ClutterInputDevice *device = NULL;
2706   ClutterMainContext  *context;
2707
2708   context = clutter_context_get_default ();
2709
2710   for (item = context->input_devices;
2711        item != NULL;
2712        item = item->next)
2713   {
2714     device = item->data;
2715
2716     if (device->id == id)
2717       return device;
2718   }
2719
2720   return NULL;
2721 }
2722
2723 /**
2724  * clutter_get_font_map:
2725  *
2726  * Retrieves the #PangoFontMap instance used by Clutter.
2727  * You can use the global font map object with the COGL
2728  * Pango API.
2729  *
2730  * Return value: the #PangoFontMap instance. The returned
2731  *   value is owned by Clutter and it should never be
2732  *   unreferenced.
2733  *
2734  * Since: 1.0
2735  */
2736 PangoFontMap *
2737 clutter_get_font_map (void)
2738 {
2739   if (CLUTTER_CONTEXT ()->font_map)
2740     return PANGO_FONT_MAP (CLUTTER_CONTEXT ()->font_map);
2741
2742   return NULL;
2743 }