Release Clutter 1.11.4 (snapshot)
[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, see <http://www.gnu.org/licenses/>.
22  */
23
24 /**
25  * SECTION:clutter-main
26  * @short_description: Various 'global' clutter functions.
27  *
28  * Functions to retrieve various global Clutter resources and other utility
29  * functions for mainloops, events and threads
30  *
31  * <refsect2 id="clutter-Threading-Model">
32  *   <title>Threading Model</title>
33  *   <para>Clutter is <emphasis>thread-aware</emphasis>: all operations
34  *   performed by Clutter are assumed to be under the big Clutter lock,
35  *   which is created when the threading is initialized through
36  *   clutter_init().</para>
37  *   <example id="example-Thread-Init">
38  *     <title>Thread Initialization</title>
39  *     <para>The code below shows how to correctly initialize Clutter
40  *     in a multi-threaded environment. These operations are mandatory for
41  *     applications that wish to use threads with Clutter.</para>
42  *     <programlisting>
43  * int
44  * main (int argc, char *argv[])
45  * {
46  *   /&ast; initialize Clutter &ast;/
47  *   clutter_init (&amp;argc, &amp;argv);
48  *
49  *   /&ast; program code &ast;/
50  *
51  *   /&ast; acquire the main lock &ast;/
52  *   clutter_threads_enter ();
53  *
54  *   /&ast; start the main loop &ast;/
55  *   clutter_main ();
56  *
57  *   /&ast; release the main lock &ast;/
58  *   clutter_threads_leave ();
59  *
60  *   /&ast; clean up &ast;/
61  *   return 0;
62  * }
63  *     </programlisting>
64  *   </example>
65  *   <para>This threading model has the caveat that it is only safe to call
66  *   Clutter's API when the lock has been acquired &mdash; which happens
67  *   between pairs of clutter_threads_enter() and clutter_threads_leave()
68  *   calls.</para>
69  *   <para>The only safe and portable way to use the Clutter API in a
70  *   multi-threaded environment is to never access the API from a thread that
71  *   did not call clutter_init() and clutter_main().</para>
72  *   <para>The common pattern for using threads with Clutter is to use worker
73  *   threads to perform blocking operations and then install idle or timeout
74  *   sources with the result when the thread finished.</para>
75  *   <para>Clutter provides thread-aware variants of g_idle_add() and
76  *   g_timeout_add() that acquire the Clutter lock before invoking the provided
77  *   callback: clutter_threads_add_idle() and
78  *   clutter_threads_add_timeout().</para>
79  *   <para>The example below shows how to use a worker thread to perform a
80  *   blocking operation, and perform UI updates using the main loop.</para>
81  *   <example id="worker-thread-example">
82  *     <title>A worker thread example</title>
83  *     <programlisting>
84  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/threads.c">
85  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
86  * </xi:include>
87  *     </programlisting>
88  *   </example>
89  * </refsect2>
90  */
91
92 #ifdef HAVE_CONFIG_H
93 #include "config.h"
94 #endif
95
96 #include <stdlib.h>
97 #include <glib/gi18n-lib.h>
98 #include <locale.h>
99
100 #include "clutter-actor.h"
101 #include "clutter-backend-private.h"
102 #include "clutter-config.h"
103 #include "clutter-debug.h"
104 #include "clutter-device-manager-private.h"
105 #include "clutter-event-private.h"
106 #include "clutter-feature.h"
107 #include "clutter-frame-source.h"
108 #include "clutter-main.h"
109 #include "clutter-master-clock.h"
110 #include "clutter-private.h"
111 #include "clutter-profile.h"
112 #include "clutter-settings-private.h"
113 #include "clutter-stage-manager.h"
114 #include "clutter-stage-private.h"
115 #include "clutter-version.h"    /* For flavour define */
116
117 #ifdef CLUTTER_WINDOWING_OSX
118 #include "osx/clutter-backend-osx.h"
119 #endif
120 #ifdef CLUTTER_WINDOWING_WIN32
121 #include "win32/clutter-backend-win32.h"
122 #endif
123 #ifdef CLUTTER_WINDOWING_GDK
124 #include "gdk/clutter-backend-gdk.h"
125 #endif
126 #ifdef CLUTTER_WINDOWING_X11
127 #include "x11/clutter-backend-x11.h"
128 #endif
129 #ifdef CLUTTER_WINDOWING_EGL
130 #include "egl/clutter-backend-eglnative.h"
131 #endif
132 #ifdef CLUTTER_WINDOWING_WAYLAND
133 #include "wayland/clutter-backend-wayland.h"
134 #endif
135
136 #include <cogl/cogl.h>
137 #include <cogl-pango/cogl-pango.h>
138
139 #include "cally.h" /* For accessibility support */
140
141 /* main context */
142 static ClutterMainContext *ClutterCntx       = NULL;
143 G_LOCK_DEFINE_STATIC (ClutterCntx);
144
145 /* main lock and locking/unlocking functions */
146 static GMutex clutter_threads_mutex;
147 static GCallback clutter_threads_lock        = NULL;
148 static GCallback clutter_threads_unlock      = NULL;
149
150 /* command line options */
151 static gboolean clutter_is_initialized       = FALSE;
152 static gboolean clutter_show_fps             = FALSE;
153 static gboolean clutter_fatal_warnings       = FALSE;
154 static gboolean clutter_disable_mipmap_text  = FALSE;
155 static gboolean clutter_use_fuzzy_picking    = FALSE;
156 static gboolean clutter_enable_accessibility = TRUE;
157 static gboolean clutter_sync_to_vblank       = TRUE;
158
159 static guint clutter_default_fps             = 60;
160
161 static ClutterTextDirection clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR;
162
163 static guint clutter_main_loop_level         = 0;
164 static GSList *main_loops                    = NULL;
165
166 /* debug flags */
167 guint clutter_debug_flags       = 0;
168 guint clutter_paint_debug_flags = 0;
169 guint clutter_pick_debug_flags  = 0;
170
171 /* profile flags */
172 guint clutter_profile_flags     = 0;
173
174 const guint clutter_major_version = CLUTTER_MAJOR_VERSION;
175 const guint clutter_minor_version = CLUTTER_MINOR_VERSION;
176 const guint clutter_micro_version = CLUTTER_MICRO_VERSION;
177
178 #ifdef CLUTTER_ENABLE_DEBUG
179 static const GDebugKey clutter_debug_keys[] = {
180   { "misc", CLUTTER_DEBUG_MISC },
181   { "actor", CLUTTER_DEBUG_ACTOR },
182   { "texture", CLUTTER_DEBUG_TEXTURE },
183   { "event", CLUTTER_DEBUG_EVENT },
184   { "paint", CLUTTER_DEBUG_PAINT },
185   { "pick", CLUTTER_DEBUG_PICK },
186   { "pango", CLUTTER_DEBUG_PANGO },
187   { "backend", CLUTTER_DEBUG_BACKEND },
188   { "scheduler", CLUTTER_DEBUG_SCHEDULER },
189   { "script", CLUTTER_DEBUG_SCRIPT },
190   { "shader", CLUTTER_DEBUG_SHADER },
191   { "animation", CLUTTER_DEBUG_ANIMATION },
192   { "layout", CLUTTER_DEBUG_LAYOUT },
193   { "clipping", CLUTTER_DEBUG_CLIPPING },
194   { "oob-transforms", CLUTTER_DEBUG_OOB_TRANSFORMS },
195 };
196 #endif /* CLUTTER_ENABLE_DEBUG */
197
198 static const GDebugKey clutter_pick_debug_keys[] = {
199   { "nop-picking", CLUTTER_DEBUG_NOP_PICKING },
200   { "dump-pick-buffers", CLUTTER_DEBUG_DUMP_PICK_BUFFERS },
201 };
202
203 static const GDebugKey clutter_paint_debug_keys[] = {
204   { "disable-swap-events", CLUTTER_DEBUG_DISABLE_SWAP_EVENTS },
205   { "disable-clipped-redraws", CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS },
206   { "redraws", CLUTTER_DEBUG_REDRAWS },
207   { "paint-volumes", CLUTTER_DEBUG_PAINT_VOLUMES },
208   { "disable-culling", CLUTTER_DEBUG_DISABLE_CULLING },
209   { "disable-offscreen-redirect", CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT },
210   { "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW },
211   { "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES },
212 };
213
214 #ifdef CLUTTER_ENABLE_PROFILE
215 static const GDebugKey clutter_profile_keys[] = {
216   {"picking-only", CLUTTER_PROFILE_PICKING_ONLY },
217   {"disable-report", CLUTTER_PROFILE_DISABLE_REPORT }
218 };
219 #endif /* CLUTTER_ENABLE_DEBUG */
220
221 static void
222 clutter_threads_impl_lock (void)
223 {
224   g_mutex_lock (&clutter_threads_mutex);
225 }
226
227 static void
228 clutter_threads_impl_unlock (void)
229 {
230   g_mutex_unlock (&clutter_threads_mutex);
231 }
232
233 static inline void
234 clutter_threads_init_default (void)
235 {
236   g_mutex_init (&clutter_threads_mutex);
237
238 #ifndef CLUTTER_WINDOWING_WIN32
239   /* we don't need nor want locking functions on Windows.here
240   * as Windows GUI system assumes multithreadedness
241   * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=662071
242   */
243   if (clutter_threads_lock == NULL)
244     clutter_threads_lock = clutter_threads_impl_lock;
245
246   if (clutter_threads_unlock == NULL)
247     clutter_threads_unlock = clutter_threads_impl_unlock;
248 #endif /* CLUTTER_WINDOWING_WIN32 */
249 }
250
251 #define ENVIRONMENT_GROUP       "Environment"
252 #define DEBUG_GROUP             "Debug"
253
254 static void
255 clutter_config_read_from_key_file (GKeyFile *keyfile)
256 {
257   GError *key_error = NULL;
258   gboolean bool_value;
259   gint int_value;
260   gchar *str_value;
261
262   if (!g_key_file_has_group (keyfile, ENVIRONMENT_GROUP))
263     return;
264
265   bool_value =
266     g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
267                             "ShowFps",
268                             &key_error);
269
270   if (key_error != NULL)
271     g_clear_error (&key_error);
272   else
273     clutter_show_fps = bool_value;
274
275   bool_value =
276     g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
277                             "DisableMipmappedText",
278                             &key_error);
279
280   if (key_error != NULL)
281     g_clear_error (&key_error);
282   else
283     clutter_disable_mipmap_text = bool_value;
284
285   bool_value =
286     g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
287                             "UseFuzzyPicking",
288                             &key_error);
289
290   if (key_error != NULL)
291     g_clear_error (&key_error);
292   else
293     clutter_use_fuzzy_picking = bool_value;
294
295   bool_value =
296     g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
297                             "EnableAccessibility",
298                             &key_error);
299
300   if (key_error != NULL)
301     g_clear_error (&key_error);
302   else
303     clutter_enable_accessibility = bool_value;
304
305   bool_value =
306     g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
307                             "SyncToVblank",
308                             &key_error);
309
310   if (key_error != NULL)
311     g_clear_error (&key_error);
312   else
313     clutter_sync_to_vblank = bool_value;
314
315   int_value =
316     g_key_file_get_integer (keyfile, ENVIRONMENT_GROUP,
317                             "DefaultFps",
318                             &key_error);
319
320   if (key_error != NULL)
321     g_clear_error (&key_error);
322   else
323     clutter_default_fps = int_value;
324
325   str_value =
326     g_key_file_get_string (keyfile, ENVIRONMENT_GROUP,
327                            "TextDirection",
328                            &key_error);
329
330   if (key_error != NULL)
331     g_clear_error (&key_error);
332   else
333     {
334       if (g_strcmp0 (str_value, "rtl") == 0)
335         clutter_text_direction = CLUTTER_TEXT_DIRECTION_RTL;
336       else
337         clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR;
338     }
339
340   g_free (str_value);
341 }
342
343 #ifdef CLUTTER_ENABLE_DEBUG
344 static void
345 clutter_debug_read_from_key_file (GKeyFile *keyfile)
346 {
347   GError *key_error = NULL;
348   gchar *value;
349
350   if (!g_key_file_has_group (keyfile, DEBUG_GROUP))
351     return;
352
353   value = g_key_file_get_value (keyfile, DEBUG_GROUP,
354                                 "Debug",
355                                 &key_error);
356   if (key_error == NULL)
357     {
358       clutter_debug_flags |=
359         g_parse_debug_string (value,
360                               clutter_debug_keys,
361                               G_N_ELEMENTS (clutter_debug_keys));
362     }
363   else
364     g_clear_error (&key_error);
365
366   g_free (value);
367
368   value = g_key_file_get_value (keyfile, DEBUG_GROUP,
369                                 "PaintDebug",
370                                 &key_error);
371   if (key_error == NULL)
372     {
373       clutter_paint_debug_flags |=
374         g_parse_debug_string (value,
375                               clutter_paint_debug_keys,
376                               G_N_ELEMENTS (clutter_paint_debug_keys));
377     }
378   else
379     g_clear_error (&key_error);
380
381   g_free (value);
382
383   value = g_key_file_get_value (keyfile, DEBUG_GROUP,
384                                 "PickDebug",
385                                 &key_error);
386   if (key_error == NULL)
387     {
388       clutter_pick_debug_flags |=
389         g_parse_debug_string (value,
390                               clutter_pick_debug_keys,
391                               G_N_ELEMENTS (clutter_pick_debug_keys));
392     }
393   else
394     g_clear_error (&key_error);
395
396   g_free (value);
397 }
398 #endif
399
400 static void
401 clutter_config_read_from_file (const gchar *config_path)
402 {
403   ClutterSettings *settings = clutter_settings_get_default ();
404   GKeyFile *key_file = g_key_file_new ();
405   GError *error = NULL;
406
407   g_key_file_load_from_file (key_file, config_path, G_KEY_FILE_NONE, &error);
408   if (error == NULL)
409     {
410       CLUTTER_NOTE (MISC, "Reading configuration from '%s'", config_path);
411
412       clutter_config_read_from_key_file (key_file);
413 #ifdef CLUTTER_ENABLE_DEBUG
414       clutter_debug_read_from_key_file (key_file);
415 #endif
416       _clutter_settings_read_from_key_file (settings, key_file);
417     }
418   else
419     {
420       g_warning ("Unable to read configuration settings from '%s': %s",
421                  config_path,
422                  error->message);
423       g_error_free (error);
424     }
425
426   g_key_file_free (key_file);
427 }
428
429 static void
430 clutter_config_read (void)
431 {
432   gchar *config_path;
433
434   config_path = g_build_filename (CLUTTER_SYSCONFDIR,
435                                   "clutter-1.0",
436                                   "settings.ini",
437                                   NULL);
438   if (g_file_test (config_path, G_FILE_TEST_EXISTS))
439     clutter_config_read_from_file (config_path);
440
441   g_free (config_path);
442
443   config_path = g_build_filename (g_get_user_config_dir (),
444                                   "clutter-1.0",
445                                   "settings.ini",
446                                   NULL);
447   if (g_file_test (config_path, G_FILE_TEST_EXISTS))
448     clutter_config_read_from_file (config_path);
449
450   g_free (config_path);
451 }
452
453 /**
454  * clutter_get_show_fps:
455  *
456  * Returns whether Clutter should print out the frames per second on the
457  * console. You can enable this setting either using the
458  * <literal>CLUTTER_SHOW_FPS</literal> environment variable or passing
459  * the <literal>--clutter-show-fps</literal> command line argument. *
460  *
461  * Return value: %TRUE if Clutter should show the FPS.
462  *
463  * Since: 0.4
464  *
465  * Deprecated: 1.10: This function does not do anything. Use the environment
466  *   variable or the configuration file to determine whether Clutter should
467  *   print out the FPS counter on the console.
468  */
469 gboolean
470 clutter_get_show_fps (void)
471 {
472   return FALSE;
473 }
474
475 gboolean
476 _clutter_context_get_show_fps (void)
477 {
478   ClutterMainContext *context = _clutter_context_get_default ();
479
480   return context->show_fps;
481 }
482
483 /**
484  * clutter_get_accessibility_enabled:
485  *
486  * Returns whether Clutter has accessibility support enabled.  As
487  * least, a value of TRUE means that there are a proper AtkUtil
488  * implementation available
489  *
490  * Return value: %TRUE if Clutter has accessibility support enabled
491  *
492  * Since: 1.4
493  */
494 gboolean
495 clutter_get_accessibility_enabled (void)
496 {
497   return cally_get_cally_initialized ();
498 }
499
500 /**
501  * clutter_redraw:
502  *
503  * Forces a redraw of the entire stage. Applications should never use this
504  * function, but queue a redraw using clutter_actor_queue_redraw().
505  *
506  * This function should only be used by libraries integrating Clutter from
507  * within another toolkit.
508  *
509  * Deprecated: 1.10: Use clutter_stage_ensure_redraw() instead.
510  */
511 void
512 clutter_redraw (ClutterStage *stage)
513 {
514   g_return_if_fail (CLUTTER_IS_STAGE (stage));
515
516   clutter_stage_ensure_redraw (stage);
517 }
518
519 /**
520  * clutter_set_motion_events_enabled:
521  * @enable: %TRUE to enable per-actor motion events
522  *
523  * Sets whether per-actor motion events should be enabled or not on
524  * all #ClutterStage<!-- -->s managed by Clutter.
525  *
526  * If @enable is %FALSE the following events will not work:
527  * <itemizedlist>
528  *   <listitem><para>ClutterActor::motion-event, unless on the
529  *     #ClutterStage</para></listitem>
530  *   <listitem><para>ClutterActor::enter-event</para></listitem>
531  *   <listitem><para>ClutterActor::leave-event</para></listitem>
532  * </itemizedlist>
533  *
534  * Since: 0.6
535  *
536  * Deprecated: 1.8: Use clutter_stage_set_motion_events_enabled() instead.
537  */
538 void
539 clutter_set_motion_events_enabled (gboolean enable)
540 {
541   ClutterStageManager *stage_manager;
542   ClutterMainContext *context;
543   const GSList *l;
544
545   enable = !!enable;
546
547   context = _clutter_context_get_default ();
548   if (context->motion_events_per_actor == enable)
549     return;
550
551   /* store the flag for later query and for newly created stages */
552   context->motion_events_per_actor = enable;
553
554   /* propagate the change to all stages */
555   stage_manager = clutter_stage_manager_get_default ();
556
557   for (l = clutter_stage_manager_peek_stages (stage_manager);
558        l != NULL;
559        l = l->next)
560     {
561       clutter_stage_set_motion_events_enabled (l->data, enable);
562     }
563 }
564
565 /**
566  * clutter_get_motion_events_enabled:
567  *
568  * Gets whether the per-actor motion events are enabled.
569  *
570  * Return value: %TRUE if the motion events are enabled
571  *
572  * Since: 0.6
573  *
574  * Deprecated: 1.8: Use clutter_stage_get_motion_events_enabled() instead.
575  */
576 gboolean
577 clutter_get_motion_events_enabled (void)
578 {
579   return _clutter_context_get_motion_events_enabled ();
580 }
581
582 ClutterActor *
583 _clutter_get_actor_by_id (ClutterStage *stage,
584                           guint32       actor_id)
585 {
586   if (stage == NULL)
587     {
588       ClutterMainContext *context = _clutter_context_get_default ();
589
590       return _clutter_id_pool_lookup (context->id_pool, actor_id);
591     }
592
593   return _clutter_stage_get_actor_by_pick_id (stage, actor_id);
594 }
595
596 void
597 _clutter_id_to_color (guint         id_,
598                       ClutterColor *col)
599 {
600   ClutterMainContext *ctx;
601   gint red, green, blue;
602
603   ctx = _clutter_context_get_default ();
604
605   if (ctx->fb_g_mask == 0)
606     {
607       /* Figure out framebuffer masks used for pick */
608       cogl_get_bitmasks (&ctx->fb_r_mask,
609                          &ctx->fb_g_mask,
610                          &ctx->fb_b_mask, NULL);
611
612       ctx->fb_r_mask_used = ctx->fb_r_mask;
613       ctx->fb_g_mask_used = ctx->fb_g_mask;
614       ctx->fb_b_mask_used = ctx->fb_b_mask;
615
616       /* XXX - describe what "fuzzy picking" is */
617       if (clutter_use_fuzzy_picking)
618         {
619           ctx->fb_r_mask_used--;
620           ctx->fb_g_mask_used--;
621           ctx->fb_b_mask_used--;
622         }
623     }
624
625   /* compute the numbers we'll store in the components */
626   red   = (id_ >> (ctx->fb_g_mask_used+ctx->fb_b_mask_used))
627         & (0xff >> (8-ctx->fb_r_mask_used));
628   green = (id_ >> ctx->fb_b_mask_used)
629         & (0xff >> (8-ctx->fb_g_mask_used));
630   blue  = (id_)
631         & (0xff >> (8-ctx->fb_b_mask_used));
632
633   /* shift left bits a bit and add one, this circumvents
634    * at least some potential rounding errors in GL/GLES
635    * driver / hw implementation.
636    */
637   if (ctx->fb_r_mask_used != ctx->fb_r_mask)
638     red = red * 2;
639   if (ctx->fb_g_mask_used != ctx->fb_g_mask)
640     green = green * 2;
641   if (ctx->fb_b_mask_used != ctx->fb_b_mask)
642     blue  = blue  * 2;
643
644   /* shift up to be full 8bit values */
645   red   = (red   << (8 - ctx->fb_r_mask)) | (0x7f >> (ctx->fb_r_mask_used));
646   green = (green << (8 - ctx->fb_g_mask)) | (0x7f >> (ctx->fb_g_mask_used));
647   blue  = (blue  << (8 - ctx->fb_b_mask)) | (0x7f >> (ctx->fb_b_mask_used));
648
649   col->red   = red;
650   col->green = green;
651   col->blue  = blue;
652   col->alpha = 0xff;
653
654   /* XXX: We rotate the nibbles of the colors here so that there is a
655    * visible variation between colors of sequential actor identifiers;
656    * otherwise pick buffers dumped to an image will pretty much just look
657    * black.
658    */
659   if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
660     {
661       col->red   = (col->red << 4)   | (col->red >> 4);
662       col->green = (col->green << 4) | (col->green >> 4);
663       col->blue  = (col->blue << 4)  | (col->blue >> 4);
664     }
665 }
666
667 guint
668 _clutter_pixel_to_id (guchar pixel[4])
669 {
670   ClutterMainContext *ctx;
671   gint red, green, blue;
672   guint retval;
673
674   ctx = _clutter_context_get_default ();
675
676   /* reduce the pixel components to the number of bits actually used of the
677    * 8bits.
678    */
679   if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
680     {
681       guchar tmp;
682
683       /* XXX: In _clutter_id_to_color we rotated the nibbles of the colors so
684        * that there is a visible variation between colors of sequential actor
685        * identifiers (otherwise pick buffers dumped to an image will pretty
686        * much just look black.) Here we reverse that rotation.
687        */
688       tmp = ((pixel[0] << 4) | (pixel[0] >> 4));
689       red = tmp >> (8 - ctx->fb_r_mask);
690       tmp = ((pixel[1] << 4) | (pixel[1] >> 4));
691       green = tmp >> (8 - ctx->fb_g_mask);
692       tmp = ((pixel[2] << 4) | (pixel[2] >> 4));
693       blue = tmp >> (8 - ctx->fb_b_mask);
694     }
695   else
696     {
697       red   = pixel[0] >> (8 - ctx->fb_r_mask);
698       green = pixel[1] >> (8 - ctx->fb_g_mask);
699       blue  = pixel[2] >> (8 - ctx->fb_b_mask);
700     }
701
702   /* divide potentially by two if 'fuzzy' */
703   red   = red   >> (ctx->fb_r_mask - ctx->fb_r_mask_used);
704   green = green >> (ctx->fb_g_mask - ctx->fb_g_mask_used);
705   blue  = blue  >> (ctx->fb_b_mask - ctx->fb_b_mask_used);
706
707   /* combine the correct per component values into the final id */
708   retval = blue
709          + (green <<  ctx->fb_b_mask_used)
710          + (red << (ctx->fb_b_mask_used + ctx->fb_g_mask_used));
711
712   return retval;
713 }
714
715 static CoglPangoFontMap *
716 clutter_context_get_pango_fontmap (void)
717 {
718   ClutterMainContext *self;
719   CoglPangoFontMap *font_map;
720   gdouble resolution;
721   gboolean use_mipmapping;
722
723   self = _clutter_context_get_default ();
724   if (G_LIKELY (self->font_map != NULL))
725     return self->font_map;
726
727   font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new ());
728
729   resolution = clutter_backend_get_resolution (self->backend);
730   cogl_pango_font_map_set_resolution (font_map, resolution);
731
732   use_mipmapping = !clutter_disable_mipmap_text;
733   cogl_pango_font_map_set_use_mipmapping (font_map, use_mipmapping);
734
735   self->font_map = font_map;
736
737   return self->font_map;
738 }
739
740 static ClutterTextDirection
741 clutter_get_text_direction (void)
742 {
743   ClutterTextDirection dir = CLUTTER_TEXT_DIRECTION_LTR;
744   const gchar *direction;
745
746   direction = g_getenv ("CLUTTER_TEXT_DIRECTION");
747   if (direction && *direction != '\0')
748     {
749       if (strcmp (direction, "rtl") == 0)
750         dir = CLUTTER_TEXT_DIRECTION_RTL;
751       else if (strcmp (direction, "ltr") == 0)
752         dir = CLUTTER_TEXT_DIRECTION_LTR;
753     }
754   else
755     {
756       /* Translators: Leave this UNTRANSLATED if your language is
757        * left-to-right.  If your language is right-to-left
758        * (e.g. Hebrew, Arabic), translate it to "default:RTL".
759        *
760        * Do NOT translate it to non-English e.g. "predefinito:LTR"! If
761        * it isn't default:LTR or default:RTL it will not work.
762        */
763       char *e = _("default:LTR");
764
765       if (strcmp (e, "default:RTL") == 0)
766         dir = CLUTTER_TEXT_DIRECTION_RTL;
767       else if (strcmp (e, "default:LTR") == 0)
768         dir = CLUTTER_TEXT_DIRECTION_LTR;
769       else
770         g_warning ("Whoever translated default:LTR did so wrongly.");
771     }
772
773   return dir;
774 }
775
776 static void
777 update_pango_context (ClutterBackend *backend,
778                       PangoContext   *context)
779 {
780   ClutterSettings *settings;
781   PangoFontDescription *font_desc;
782   const cairo_font_options_t *font_options;
783   gchar *font_name;
784   PangoDirection pango_dir;
785   gdouble resolution;
786
787   settings = clutter_settings_get_default ();
788
789   /* update the text direction */
790   if (clutter_text_direction == CLUTTER_TEXT_DIRECTION_RTL)
791     pango_dir = PANGO_DIRECTION_RTL;
792   else
793     pango_dir = PANGO_DIRECTION_LTR;
794
795   pango_context_set_base_dir (context, pango_dir);
796
797   g_object_get (settings, "font-name", &font_name, NULL);
798
799   /* get the configuration for the PangoContext from the backend */
800   font_options = clutter_backend_get_font_options (backend);
801   resolution = clutter_backend_get_resolution (backend);
802
803   font_desc = pango_font_description_from_string (font_name);
804
805   if (resolution < 0)
806     resolution = 96.0; /* fall back */
807
808   pango_context_set_font_description (context, font_desc);
809   pango_cairo_context_set_font_options (context, font_options);
810   pango_cairo_context_set_resolution (context, resolution);
811
812   pango_font_description_free (font_desc);
813   g_free (font_name);
814 }
815
816 PangoContext *
817 _clutter_context_get_pango_context (void)
818 {
819   ClutterMainContext *self = _clutter_context_get_default ();
820
821   if (G_UNLIKELY (self->pango_context == NULL))
822     {
823       PangoContext *context;
824
825       context = _clutter_context_create_pango_context ();
826       self->pango_context = context;
827
828       g_signal_connect (self->backend, "resolution-changed",
829                         G_CALLBACK (update_pango_context),
830                         self->pango_context);
831       g_signal_connect (self->backend, "font-changed",
832                         G_CALLBACK (update_pango_context),
833                         self->pango_context);
834     }
835   else
836     update_pango_context (self->backend, self->pango_context);
837
838   return self->pango_context;
839 }
840
841 PangoContext *
842 _clutter_context_create_pango_context (void)
843 {
844   CoglPangoFontMap *font_map;
845   PangoContext *context;
846
847   font_map = clutter_context_get_pango_fontmap ();
848
849   context = cogl_pango_font_map_create_context (font_map);
850   update_pango_context (clutter_get_default_backend (), context);
851   pango_context_set_language (context, pango_language_get_default ());
852
853   return context;
854 }
855
856 /**
857  * clutter_main_quit:
858  *
859  * Terminates the Clutter mainloop.
860  */
861 void
862 clutter_main_quit (void)
863 {
864   g_return_if_fail (main_loops != NULL);
865
866   g_main_loop_quit (main_loops->data);
867 }
868
869 /**
870  * clutter_main_level:
871  *
872  * Retrieves the depth of the Clutter mainloop.
873  *
874  * Return value: The level of the mainloop.
875  */
876 gint
877 clutter_main_level (void)
878 {
879   return clutter_main_loop_level;
880 }
881
882 #ifdef CLUTTER_ENABLE_PROFILE
883 static gint (*prev_poll) (GPollFD *ufds, guint nfsd, gint timeout_) = NULL;
884
885 static gint
886 timed_poll (GPollFD *ufds,
887             guint nfsd,
888             gint timeout_)
889 {
890   gint ret;
891   CLUTTER_STATIC_TIMER (poll_timer,
892                         "Mainloop", /* parent */
893                         "Mainloop Idle",
894                         "The time spent idle in poll()",
895                         0 /* no application private data */);
896
897   CLUTTER_TIMER_START (uprof_get_mainloop_context (), poll_timer);
898   ret = prev_poll (ufds, nfsd, timeout_);
899   CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), poll_timer);
900   return ret;
901 }
902 #endif
903
904 /**
905  * clutter_main:
906  *
907  * Starts the Clutter mainloop.
908  */
909 void
910 clutter_main (void)
911 {
912   GMainLoop *loop;
913   CLUTTER_STATIC_TIMER (mainloop_timer,
914                         NULL, /* no parent */
915                         "Mainloop",
916                         "The time spent in the clutter mainloop",
917                         0 /* no application private data */);
918
919   if (clutter_main_loop_level == 0)
920     CLUTTER_TIMER_START (uprof_get_mainloop_context (), mainloop_timer);
921
922   if (!_clutter_context_is_initialized ())
923     {
924       g_warning ("Called clutter_main() but Clutter wasn't initialised. "
925                  "You must call clutter_init() first.");
926       return;
927     }
928
929   clutter_main_loop_level++;
930
931 #ifdef CLUTTER_ENABLE_PROFILE
932   if (!prev_poll)
933     {
934       prev_poll = g_main_context_get_poll_func (NULL);
935       g_main_context_set_poll_func (NULL, timed_poll);
936     }
937 #endif
938
939   loop = g_main_loop_new (NULL, TRUE);
940   main_loops = g_slist_prepend (main_loops, loop);
941
942   if (g_main_loop_is_running (main_loops->data))
943     {
944       clutter_threads_leave ();
945       g_main_loop_run (loop);
946       clutter_threads_enter ();
947     }
948
949   main_loops = g_slist_remove (main_loops, loop);
950
951   g_main_loop_unref (loop);
952
953   clutter_main_loop_level--;
954
955   if (clutter_main_loop_level == 0)
956     CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer);
957 }
958
959 /**
960  * clutter_threads_init:
961  *
962  * Initialises the Clutter threading mechanism, so that Clutter API can be
963  * called by multiple threads, using clutter_threads_enter() and
964  * clutter_threads_leave() to mark the critical sections.
965  *
966  * You must call g_thread_init() before this function.
967  *
968  * This function must be called before clutter_init().
969  *
970  * It is safe to call this function multiple times.
971  *
972  * Since: 0.4
973  *
974  * Deprecated: 1.10: This function does not do anything. Threading support
975  *   is initialized when Clutter is initialized.
976  */
977 void
978 clutter_threads_init (void)
979 {
980 }
981
982 /**
983  * clutter_threads_set_lock_functions: (skip)
984  * @enter_fn: function called when aquiring the Clutter main lock
985  * @leave_fn: function called when releasing the Clutter main lock
986  *
987  * Allows the application to replace the standard method that
988  * Clutter uses to protect its data structures. Normally, Clutter
989  * creates a single #GMutex that is locked by clutter_threads_enter(),
990  * and released by clutter_threads_leave(); using this function an
991  * application provides, instead, a function @enter_fn that is
992  * called by clutter_threads_enter() and a function @leave_fn that is
993  * called by clutter_threads_leave().
994  *
995  * The functions must provide at least same locking functionality
996  * as the default implementation, but can also do extra application
997  * specific processing.
998  *
999  * As an example, consider an application that has its own recursive
1000  * lock that when held, holds the Clutter lock as well. When Clutter
1001  * unlocks the Clutter lock when entering a recursive main loop, the
1002  * application must temporarily release its lock as well.
1003  *
1004  * Most threaded Clutter apps won't need to use this method.
1005  *
1006  * This method must be called before clutter_init(), and cannot
1007  * be called multiple times.
1008  *
1009  * Since: 0.4
1010  */
1011 void
1012 clutter_threads_set_lock_functions (GCallback enter_fn,
1013                                     GCallback leave_fn)
1014 {
1015   g_return_if_fail (clutter_threads_lock == NULL &&
1016                     clutter_threads_unlock == NULL);
1017
1018   clutter_threads_lock = enter_fn;
1019   clutter_threads_unlock = leave_fn;
1020 }
1021
1022 gboolean
1023 _clutter_threads_dispatch (gpointer data)
1024 {
1025   ClutterThreadsDispatch *dispatch = data;
1026   gboolean ret = FALSE;
1027
1028   clutter_threads_enter ();
1029
1030   if (!g_source_is_destroyed (g_main_current_source ()))
1031     ret = dispatch->func (dispatch->data);
1032
1033   clutter_threads_leave ();
1034
1035   return ret;
1036 }
1037
1038 void
1039 _clutter_threads_dispatch_free (gpointer data)
1040 {
1041   ClutterThreadsDispatch *dispatch = data;
1042
1043   /* XXX - we cannot hold the thread lock here because the main loop
1044    * might destroy a source while still in the dispatcher function; so
1045    * knowing whether the lock is being held or not is not known a priori.
1046    *
1047    * see bug: http://bugzilla.gnome.org/show_bug.cgi?id=459555
1048    */
1049   if (dispatch->notify)
1050     dispatch->notify (dispatch->data);
1051
1052   g_slice_free (ClutterThreadsDispatch, dispatch);
1053 }
1054
1055 /**
1056  * clutter_threads_add_idle_full:
1057  * @priority: the priority of the timeout source. Typically this will be in the
1058  *    range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
1059  * @func: function to call
1060  * @data: data to pass to the function
1061  * @notify: functio to call when the idle source is removed
1062  *
1063  * Adds a function to be called whenever there are no higher priority
1064  * events pending. If the function returns %FALSE it is automatically
1065  * removed from the list of event sources and will not be called again.
1066  *
1067  * This function can be considered a thread-safe variant of g_idle_add_full():
1068  * it will call @function while holding the Clutter lock. It is logically
1069  * equivalent to the following implementation:
1070  *
1071  * |[
1072  * static gboolean
1073  * idle_safe_callback (gpointer data)
1074  * {
1075  *    SafeClosure *closure = data;
1076  *    gboolean res = FALSE;
1077  *
1078  *    /&ast; mark the critical section &ast;/
1079  *
1080  *    clutter_threads_enter();
1081  *
1082  *    /&ast; the callback does not need to acquire the Clutter
1083  *     &ast; lock itself, as it is held by the this proxy handler
1084  *     &ast;/
1085  *    res = closure->callback (closure->data);
1086  *
1087  *    clutter_threads_leave();
1088  *
1089  *    return res;
1090  * }
1091  * static gulong
1092  * add_safe_idle (GSourceFunc callback,
1093  *                gpointer    data)
1094  * {
1095  *   SafeClosure *closure = g_new0 (SafeClosure, 1);
1096  *
1097  *   closure-&gt;callback = callback;
1098  *   closure-&gt;data = data;
1099  *
1100  *   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1101  *                           idle_safe_callback,
1102  *                           closure,
1103  *                           g_free)
1104  * }
1105  *]|
1106  *
1107  * This function should be used by threaded applications to make sure
1108  * that @func is emitted under the Clutter threads lock and invoked
1109  * from the same thread that started the Clutter main loop. For instance,
1110  * it can be used to update the UI using the results from a worker
1111  * thread:
1112  *
1113  * |[
1114  * static gboolean
1115  * update_ui (gpointer data)
1116  * {
1117  *   SomeClosure *closure = data;
1118  *
1119  *   /&ast; it is safe to call Clutter API from this function because
1120  *    &ast; it is invoked from the same thread that started the main
1121  *    &ast; loop and under the Clutter thread lock
1122  *    &ast;/
1123  *   clutter_label_set_text (CLUTTER_LABEL (closure-&gt;label),
1124  *                           closure-&gt;text);
1125  *
1126  *   g_object_unref (closure-&gt;label);
1127  *   g_free (closure);
1128  *
1129  *   return FALSE;
1130  * }
1131  *
1132  *   /&ast; within another thread &ast;/
1133  *   closure = g_new0 (SomeClosure, 1);
1134  *   /&ast; always take a reference on GObject instances &ast;/
1135  *   closure-&gt;label = g_object_ref (my_application-&gt;label);
1136  *   closure-&gt;text = g_strdup (processed_text_to_update_the_label);
1137  *
1138  *   clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE,
1139  *                                  update_ui,
1140  *                                  closure,
1141  *                                  NULL);
1142  * ]|
1143  *
1144  * Rename to: clutter_threads_add_idle
1145  *
1146  * Return value: the ID (greater than 0) of the event source.
1147  *
1148  * Since: 0.4
1149  */
1150 guint
1151 clutter_threads_add_idle_full (gint           priority,
1152                                GSourceFunc    func,
1153                                gpointer       data,
1154                                GDestroyNotify notify)
1155 {
1156   ClutterThreadsDispatch *dispatch;
1157
1158   g_return_val_if_fail (func != NULL, 0);
1159
1160   dispatch = g_slice_new (ClutterThreadsDispatch);
1161   dispatch->func = func;
1162   dispatch->data = data;
1163   dispatch->notify = notify;
1164
1165   return g_idle_add_full (priority,
1166                           _clutter_threads_dispatch, dispatch,
1167                           _clutter_threads_dispatch_free);
1168 }
1169
1170 /**
1171  * clutter_threads_add_idle: (skip)
1172  * @func: function to call
1173  * @data: data to pass to the function
1174  *
1175  * Simple wrapper around clutter_threads_add_idle_full() using the
1176  * default priority.
1177  *
1178  * Return value: the ID (greater than 0) of the event source.
1179  *
1180  * Since: 0.4
1181  */
1182 guint
1183 clutter_threads_add_idle (GSourceFunc func,
1184                           gpointer    data)
1185 {
1186   g_return_val_if_fail (func != NULL, 0);
1187
1188   return clutter_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
1189                                         func, data,
1190                                         NULL);
1191 }
1192
1193 /**
1194  * clutter_threads_add_timeout_full:
1195  * @priority: the priority of the timeout source. Typically this will be in the
1196  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
1197  * @interval: the time between calls to the function, in milliseconds
1198  * @func: function to call
1199  * @data: data to pass to the function
1200  * @notify: function to call when the timeout source is removed
1201  *
1202  * Sets a function to be called at regular intervals holding the Clutter
1203  * threads lock, with the given priority. The function is called repeatedly
1204  * until it returns %FALSE, at which point the timeout is automatically
1205  * removed and the function will not be called again. The @notify function
1206  * is called when the timeout is removed.
1207  *
1208  * The first call to the function will be at the end of the first @interval.
1209  *
1210  * It is important to note that, due to how the Clutter main loop is
1211  * implemented, the timing will not be accurate and it will not try to
1212  * "keep up" with the interval.
1213  *
1214  * See also clutter_threads_add_idle_full().
1215  *
1216  * Rename to: clutter_threads_add_timeout
1217  *
1218  * Return value: the ID (greater than 0) of the event source.
1219  *
1220  * Since: 0.4
1221  */
1222 guint
1223 clutter_threads_add_timeout_full (gint           priority,
1224                                   guint          interval,
1225                                   GSourceFunc    func,
1226                                   gpointer       data,
1227                                   GDestroyNotify notify)
1228 {
1229   ClutterThreadsDispatch *dispatch;
1230
1231   g_return_val_if_fail (func != NULL, 0);
1232
1233   dispatch = g_slice_new (ClutterThreadsDispatch);
1234   dispatch->func = func;
1235   dispatch->data = data;
1236   dispatch->notify = notify;
1237
1238   return g_timeout_add_full (priority,
1239                              interval,
1240                              _clutter_threads_dispatch, dispatch,
1241                              _clutter_threads_dispatch_free);
1242 }
1243
1244 /**
1245  * clutter_threads_add_timeout: (skip)
1246  * @interval: the time between calls to the function, in milliseconds
1247  * @func: function to call
1248  * @data: data to pass to the function
1249  *
1250  * Simple wrapper around clutter_threads_add_timeout_full().
1251  *
1252  * Return value: the ID (greater than 0) of the event source.
1253  *
1254  * Since: 0.4
1255  */
1256 guint
1257 clutter_threads_add_timeout (guint       interval,
1258                              GSourceFunc func,
1259                              gpointer    data)
1260 {
1261   g_return_val_if_fail (func != NULL, 0);
1262
1263   return clutter_threads_add_timeout_full (G_PRIORITY_DEFAULT,
1264                                            interval,
1265                                            func, data,
1266                                            NULL);
1267 }
1268
1269 /**
1270  * clutter_threads_enter:
1271  *
1272  * Locks the Clutter thread lock.
1273  *
1274  * Since: 0.4
1275  */
1276 void
1277 clutter_threads_enter (void)
1278 {
1279   if (clutter_threads_lock != NULL)
1280     (* clutter_threads_lock) ();
1281 }
1282
1283 /**
1284  * clutter_threads_leave:
1285  *
1286  * Unlocks the Clutter thread lock.
1287  *
1288  * Since: 0.4
1289  */
1290 void
1291 clutter_threads_leave (void)
1292 {
1293   if (clutter_threads_unlock != NULL)
1294     (* clutter_threads_unlock) ();
1295 }
1296
1297
1298 /**
1299  * clutter_get_debug_enabled:
1300  *
1301  * Check if Clutter has debugging enabled.
1302  *
1303  * Return value: %FALSE
1304  *
1305  * Deprecated: 1.10: This function does not do anything.
1306  */
1307 gboolean
1308 clutter_get_debug_enabled (void)
1309 {
1310   return FALSE;
1311 }
1312
1313 void
1314 _clutter_context_lock (void)
1315 {
1316   G_LOCK (ClutterCntx);
1317 }
1318
1319 void
1320 _clutter_context_unlock (void)
1321 {
1322   G_UNLOCK (ClutterCntx);
1323 }
1324
1325 gboolean
1326 _clutter_context_is_initialized (void)
1327 {
1328   if (ClutterCntx == NULL)
1329     return FALSE;
1330
1331   return ClutterCntx->is_initialized;
1332 }
1333
1334 static ClutterBackend *
1335 clutter_create_backend (void)
1336 {
1337   const char *backend = g_getenv ("CLUTTER_BACKEND");
1338   ClutterBackend *retval = NULL;
1339
1340   if (backend != NULL)
1341     backend = g_intern_string (backend);
1342
1343 #ifdef CLUTTER_WINDOWING_OSX
1344   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_OSX))
1345     retval = g_object_new (CLUTTER_TYPE_BACKEND_OSX, NULL);
1346   else
1347 #endif
1348 #ifdef CLUTTER_WINDOWING_WIN32
1349   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_WIN32))
1350     retval = g_object_new (CLUTTER_TYPE_BACKEND_WIN32, NULL);
1351   else
1352 #endif
1353 #ifdef CLUTTER_WINDOWING_WAYLAND
1354   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_WAYLAND))
1355     retval = g_object_new (CLUTTER_TYPE_BACKEND_WAYLAND, NULL);
1356   else
1357 #endif
1358 #ifdef CLUTTER_WINDOWING_EGL
1359   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_EGL))
1360     retval = g_object_new (CLUTTER_TYPE_BACKEND_EGL_NATIVE, NULL);
1361   else
1362 #endif
1363 #ifdef CLUTTER_WINDOWING_X11
1364   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_X11))
1365     retval = g_object_new (CLUTTER_TYPE_BACKEND_X11, NULL);
1366   else
1367 #endif
1368 #ifdef CLUTTER_WINDOWING_GDK
1369   if (backend == NULL || backend == I_(CLUTTER_WINDOWING_GDK))
1370     retval = g_object_new (CLUTTER_TYPE_BACKEND_GDK, NULL);
1371   else
1372 #endif
1373   if (backend == NULL)
1374     g_error ("No default Clutter backend found.");
1375   else
1376     g_error ("Unsupported Clutter backend: '%s'", backend);
1377
1378   return retval;
1379 }
1380
1381 static ClutterMainContext *
1382 clutter_context_get_default_unlocked (void)
1383 {
1384   if (G_UNLIKELY (ClutterCntx == NULL))
1385     {
1386       ClutterMainContext *ctx;
1387
1388       ClutterCntx = ctx = g_new0 (ClutterMainContext, 1);
1389
1390       ctx->is_initialized = FALSE;
1391
1392       /* create the windowing system backend */
1393       ctx->backend = clutter_create_backend ();
1394
1395       /* create the default settings object, and store a back pointer to
1396        * the backend singleton
1397        */
1398       ctx->settings = clutter_settings_get_default ();
1399       _clutter_settings_set_backend (ctx->settings, ctx->backend);
1400
1401       ctx->motion_events_per_actor = TRUE;
1402       ctx->last_repaint_id = 1;
1403     }
1404
1405   return ClutterCntx;
1406 }
1407
1408 ClutterMainContext *
1409 _clutter_context_get_default (void)
1410 {
1411   ClutterMainContext *retval;
1412
1413   _clutter_context_lock ();
1414
1415   retval = clutter_context_get_default_unlocked ();
1416
1417   _clutter_context_unlock ();
1418
1419   return retval;
1420 }
1421
1422 /**
1423  * clutter_get_timestamp:
1424  *
1425  * Returns the approximate number of microseconds passed since Clutter was
1426  * intialised.
1427  *
1428  * This function shdould not be used by application code.
1429  *
1430  * The output of this function depends on whether Clutter was configured to
1431  * enable its debugging code paths, so it's less useful than intended.
1432  *
1433  * Since Clutter 1.10, this function is an alias to g_get_monotonic_time()
1434  * if Clutter was configured to enable the debugging code paths.
1435  *
1436  * Return value: Number of microseconds since clutter_init() was called, or
1437  *   zero if Clutter was not configured with debugging code paths.
1438  *
1439  * Deprecated: 1.10: Use #GTimer or g_get_monotonic_time() for a proper
1440  *   timing source
1441  */
1442 gulong
1443 clutter_get_timestamp (void)
1444 {
1445 #ifdef CLUTTER_ENABLE_DEBUG
1446   return (gulong) g_get_monotonic_time ();
1447 #else
1448   return 0L;
1449 #endif
1450 }
1451
1452 static gboolean
1453 clutter_arg_direction_cb (const char *key,
1454                           const char *value,
1455                           gpointer    user_data)
1456 {
1457   clutter_text_direction =
1458     (strcmp (value, "rtl") == 0) ? CLUTTER_TEXT_DIRECTION_RTL
1459                                  : CLUTTER_TEXT_DIRECTION_LTR;
1460
1461   return TRUE;
1462 }
1463
1464 #ifdef CLUTTER_ENABLE_DEBUG
1465 static gboolean
1466 clutter_arg_debug_cb (const char *key,
1467                       const char *value,
1468                       gpointer    user_data)
1469 {
1470   clutter_debug_flags |=
1471     g_parse_debug_string (value,
1472                           clutter_debug_keys,
1473                           G_N_ELEMENTS (clutter_debug_keys));
1474   return TRUE;
1475 }
1476
1477 static gboolean
1478 clutter_arg_no_debug_cb (const char *key,
1479                          const char *value,
1480                          gpointer    user_data)
1481 {
1482   clutter_debug_flags &=
1483     ~g_parse_debug_string (value,
1484                            clutter_debug_keys,
1485                            G_N_ELEMENTS (clutter_debug_keys));
1486   return TRUE;
1487 }
1488 #endif /* CLUTTER_ENABLE_DEBUG */
1489
1490 #ifdef CLUTTER_ENABLE_PROFILE
1491 static gboolean
1492 clutter_arg_profile_cb (const char *key,
1493                         const char *value,
1494                         gpointer    user_data)
1495 {
1496   clutter_profile_flags |=
1497     g_parse_debug_string (value,
1498                           clutter_profile_keys,
1499                           G_N_ELEMENTS (clutter_profile_keys));
1500   return TRUE;
1501 }
1502
1503 static gboolean
1504 clutter_arg_no_profile_cb (const char *key,
1505                            const char *value,
1506                            gpointer    user_data)
1507 {
1508   clutter_profile_flags &=
1509     ~g_parse_debug_string (value,
1510                            clutter_profile_keys,
1511                            G_N_ELEMENTS (clutter_profile_keys));
1512   return TRUE;
1513 }
1514 #endif /* CLUTTER_ENABLE_PROFILE */
1515
1516 GQuark
1517 clutter_init_error_quark (void)
1518 {
1519   return g_quark_from_static_string ("clutter-init-error-quark");
1520 }
1521
1522 static ClutterInitError
1523 clutter_init_real (GError **error)
1524 {
1525   ClutterMainContext *ctx;
1526   ClutterBackend *backend;
1527
1528   /* Note, creates backend if not already existing, though parse args will
1529    * have likely created it
1530    */
1531   ctx = _clutter_context_get_default ();
1532   backend = ctx->backend;
1533
1534   if (!ctx->options_parsed)
1535     {
1536       if (error)
1537         g_set_error (error, CLUTTER_INIT_ERROR,
1538                      CLUTTER_INIT_ERROR_INTERNAL,
1539                      "When using clutter_get_option_group_without_init() "
1540                      "you must parse options before calling clutter_init()");
1541       else
1542         g_critical ("When using clutter_get_option_group_without_init() "
1543                     "you must parse options before calling clutter_init()");
1544
1545       return CLUTTER_INIT_ERROR_INTERNAL;
1546     }
1547
1548   /*
1549    * Call backend post parse hooks.
1550    */
1551   if (!_clutter_backend_post_parse (backend, error))
1552     return CLUTTER_INIT_ERROR_BACKEND;
1553
1554   /* If we are displaying the regions that would get redrawn with clipped
1555    * redraws enabled we actually have to disable the clipped redrawing
1556    * because otherwise we end up with nasty trails of rectangles everywhere.
1557    */
1558   if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)
1559     clutter_paint_debug_flags |= CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS;
1560
1561   /* The same is true when drawing the outlines of paint volumes... */
1562   if (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES)
1563     {
1564       clutter_paint_debug_flags |=
1565         CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS | CLUTTER_DEBUG_DISABLE_CULLING;
1566     }
1567
1568   /* this will take care of initializing Cogl's state and
1569    * query the GL machinery for features
1570    */
1571   if (!_clutter_feature_init (error))
1572     return CLUTTER_INIT_ERROR_BACKEND;
1573
1574 #ifdef CLUTTER_ENABLE_PROFILE
1575   /* We need to be absolutely sure that uprof has been initialized
1576    * before calling _clutter_uprof_init. uprof_init (NULL, NULL)
1577    * will be a NOP if it has been initialized but it will also
1578    * mean subsequent parsing of the UProf GOptionGroup will have no
1579    * affect.
1580    *
1581    * Sadly GOptionGroup based library initialization is extremly
1582    * fragile by design because GOptionGroups have no notion of
1583    * dependencies and our post_parse_hook may be called before
1584    * the cogl or uprof groups get parsed.
1585    */
1586   uprof_init (NULL, NULL);
1587   _clutter_uprof_init ();
1588
1589   if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
1590     _clutter_profile_suspend ();
1591 #endif
1592
1593   clutter_text_direction = clutter_get_text_direction ();
1594
1595   /* Initiate event collection */
1596   _clutter_backend_init_events (ctx->backend);
1597
1598   clutter_is_initialized = TRUE;
1599   ctx->is_initialized = TRUE;
1600
1601   /* Initialize a11y */
1602   if (clutter_enable_accessibility)
1603     cally_accessibility_init ();
1604
1605   return CLUTTER_INIT_SUCCESS;
1606 }
1607
1608 static GOptionEntry clutter_args[] = {
1609   { "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
1610     N_("Show frames per second"), NULL },
1611   { "clutter-default-fps", 0, 0, G_OPTION_ARG_INT, &clutter_default_fps,
1612     N_("Default frame rate"), "FPS" },
1613   { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings,
1614     N_("Make all warnings fatal"), NULL },
1615   { "clutter-text-direction", 0, 0, G_OPTION_ARG_CALLBACK,
1616     clutter_arg_direction_cb,
1617     N_("Direction for the text"), "DIRECTION" },
1618   { "clutter-disable-mipmapped-text", 0, 0, G_OPTION_ARG_NONE,
1619     &clutter_disable_mipmap_text,
1620     N_("Disable mipmapping on text"), NULL },
1621   { "clutter-use-fuzzy-picking", 0, 0, G_OPTION_ARG_NONE,
1622     &clutter_use_fuzzy_picking,
1623     N_("Use 'fuzzy' picking"), NULL },
1624 #ifdef CLUTTER_ENABLE_DEBUG
1625   { "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
1626     N_("Clutter debugging flags to set"), "FLAGS" },
1627   { "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb,
1628     N_("Clutter debugging flags to unset"), "FLAGS" },
1629 #endif /* CLUTTER_ENABLE_DEBUG */
1630 #ifdef CLUTTER_ENABLE_PROFILE
1631   { "clutter-profile", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_profile_cb,
1632     N_("Clutter profiling flags to set"), "FLAGS" },
1633   { "clutter-no-profile", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_profile_cb,
1634     N_("Clutter profiling flags to unset"), "FLAGS" },
1635 #endif /* CLUTTER_ENABLE_PROFILE */
1636   { "clutter-enable-accessibility", 0, 0, G_OPTION_ARG_NONE, &clutter_enable_accessibility,
1637     N_("Enable accessibility"), NULL },
1638   { NULL, },
1639 };
1640
1641 /* pre_parse_hook: initialise variables depending on environment
1642  * variables; these variables might be overridden by the command
1643  * line arguments that are going to be parsed after.
1644  */
1645 static gboolean
1646 pre_parse_hook (GOptionContext  *context,
1647                 GOptionGroup    *group,
1648                 gpointer         data,
1649                 GError         **error)
1650 {
1651   ClutterMainContext *clutter_context;
1652   ClutterBackend *backend;
1653   const char *env_string;
1654
1655   if (clutter_is_initialized)
1656     return TRUE;
1657
1658   if (setlocale (LC_ALL, "") == NULL)
1659     g_warning ("Locale not supported by C library.\n"
1660                "Using the fallback 'C' locale.");
1661
1662   /* read the configuration file, if it exists; the configuration file
1663    * determines the initial state of the settings, so that command line
1664    * arguments can override them.
1665    */
1666   clutter_config_read ();
1667
1668   clutter_context = _clutter_context_get_default ();
1669
1670   clutter_context->id_pool = _clutter_id_pool_new (256);
1671
1672   backend = clutter_context->backend;
1673   g_assert (CLUTTER_IS_BACKEND (backend));
1674
1675 #ifdef CLUTTER_ENABLE_DEBUG
1676   env_string = g_getenv ("CLUTTER_DEBUG");
1677   if (env_string != NULL)
1678     {
1679       clutter_debug_flags =
1680         g_parse_debug_string (env_string,
1681                               clutter_debug_keys,
1682                               G_N_ELEMENTS (clutter_debug_keys));
1683       env_string = NULL;
1684     }
1685 #endif /* CLUTTER_ENABLE_DEBUG */
1686
1687 #ifdef CLUTTER_ENABLE_PROFILE
1688   env_string = g_getenv ("CLUTTER_PROFILE");
1689   if (env_string != NULL)
1690     {
1691       clutter_profile_flags =
1692         g_parse_debug_string (env_string,
1693                               clutter_profile_keys,
1694                               G_N_ELEMENTS (clutter_profile_keys));
1695       env_string = NULL;
1696     }
1697 #endif /* CLUTTER_ENABLE_PROFILE */
1698
1699   env_string = g_getenv ("CLUTTER_PICK");
1700   if (env_string != NULL)
1701     {
1702       clutter_pick_debug_flags =
1703         g_parse_debug_string (env_string,
1704                               clutter_pick_debug_keys,
1705                               G_N_ELEMENTS (clutter_pick_debug_keys));
1706       env_string = NULL;
1707     }
1708
1709   env_string = g_getenv ("CLUTTER_PAINT");
1710   if (env_string != NULL)
1711     {
1712       clutter_paint_debug_flags =
1713         g_parse_debug_string (env_string,
1714                               clutter_paint_debug_keys,
1715                               G_N_ELEMENTS (clutter_paint_debug_keys));
1716       env_string = NULL;
1717     }
1718
1719   env_string = g_getenv ("CLUTTER_SHOW_FPS");
1720   if (env_string)
1721     clutter_show_fps = TRUE;
1722
1723   env_string = g_getenv ("CLUTTER_DEFAULT_FPS");
1724   if (env_string)
1725     {
1726       gint default_fps = g_ascii_strtoll (env_string, NULL, 10);
1727
1728       clutter_default_fps = CLAMP (default_fps, 1, 1000);
1729     }
1730
1731   env_string = g_getenv ("CLUTTER_DISABLE_MIPMAPPED_TEXT");
1732   if (env_string)
1733     clutter_disable_mipmap_text = TRUE;
1734
1735   env_string = g_getenv ("CLUTTER_FUZZY_PICK");
1736   if (env_string)
1737     clutter_use_fuzzy_picking = TRUE;
1738
1739   env_string = g_getenv ("CLUTTER_VBLANK");
1740   if (g_strcmp0 (env_string, "none") == 0)
1741     clutter_sync_to_vblank = FALSE;
1742
1743   return _clutter_backend_pre_parse (backend, error);
1744 }
1745
1746 /* post_parse_hook: initialise the context and data structures
1747  * and opens the X display
1748  */
1749 static gboolean
1750 post_parse_hook (GOptionContext  *context,
1751                  GOptionGroup    *group,
1752                  gpointer         data,
1753                  GError         **error)
1754 {
1755   ClutterMainContext *clutter_context;
1756   ClutterBackend *backend;
1757
1758   if (clutter_is_initialized)
1759     return TRUE;
1760
1761   clutter_context = _clutter_context_get_default ();
1762   backend = clutter_context->backend;
1763   g_assert (CLUTTER_IS_BACKEND (backend));
1764
1765   if (clutter_fatal_warnings)
1766     {
1767       GLogLevelFlags fatal_mask;
1768
1769       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
1770       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
1771       g_log_set_always_fatal (fatal_mask);
1772     }
1773
1774   clutter_context->frame_rate = clutter_default_fps;
1775   clutter_context->show_fps = clutter_show_fps;
1776   clutter_context->options_parsed = TRUE;
1777
1778   /* If not asked to defer display setup, call clutter_init_real(),
1779    * which in turn calls the backend post parse hooks.
1780    */
1781   if (!clutter_context->defer_display_setup)
1782     return clutter_init_real (error) == CLUTTER_INIT_SUCCESS;
1783
1784   return TRUE;
1785 }
1786
1787 /**
1788  * clutter_get_option_group: (skip)
1789  *
1790  * Returns a #GOptionGroup for the command line arguments recognized
1791  * by Clutter. You should add this group to your #GOptionContext with
1792  * g_option_context_add_group(), if you are using g_option_context_parse()
1793  * to parse your commandline arguments.
1794  *
1795  * Calling g_option_context_parse() with Clutter's #GOptionGroup will result
1796  * in Clutter's initialization. That is, the following code:
1797  *
1798  * |[
1799  *   g_option_context_set_main_group (context, clutter_get_option_group ());
1800  *   res = g_option_context_parse (context, &amp;argc, &amp;argc, NULL);
1801  * ]|
1802  *
1803  * is functionally equivalent to:
1804  *
1805  * |[
1806  *   clutter_init (&amp;argc, &amp;argv);
1807  * ]|
1808  *
1809  * After g_option_context_parse() on a #GOptionContext containing the
1810  * Clutter #GOptionGroup has returned %TRUE, Clutter is guaranteed to be
1811  * initialized.
1812  *
1813  * Return value: (transfer full): a #GOptionGroup for the commandline arguments
1814  *   recognized by Clutter
1815  *
1816  * Since: 0.2
1817  */
1818 GOptionGroup *
1819 clutter_get_option_group (void)
1820 {
1821   ClutterMainContext *context;
1822   GOptionGroup *group;
1823
1824   clutter_base_init ();
1825
1826   context = _clutter_context_get_default ();
1827
1828   group = g_option_group_new ("clutter",
1829                               _("Clutter Options"),
1830                               _("Show Clutter Options"),
1831                               NULL,
1832                               NULL);
1833
1834   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
1835   g_option_group_add_entries (group, clutter_args);
1836   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
1837
1838   /* add backend-specific options */
1839   _clutter_backend_add_options (context->backend, group);
1840
1841   return group;
1842 }
1843
1844 /**
1845  * clutter_get_option_group_without_init: (skip)
1846  *
1847  * Returns a #GOptionGroup for the command line arguments recognized
1848  * by Clutter. You should add this group to your #GOptionContext with
1849  * g_option_context_add_group(), if you are using g_option_context_parse()
1850  * to parse your commandline arguments.
1851  *
1852  * Unlike clutter_get_option_group(), calling g_option_context_parse() with
1853  * the #GOptionGroup returned by this function requires a subsequent explicit
1854  * call to clutter_init(); use this function when needing to set foreign
1855  * display connection with clutter_x11_set_display(), or with
1856  * <function>gtk_clutter_init()</function>.
1857  *
1858  * Return value: (transfer full): a #GOptionGroup for the commandline arguments
1859  *   recognized by Clutter
1860  *
1861  * Since: 0.8.2
1862  */
1863 GOptionGroup *
1864 clutter_get_option_group_without_init (void)
1865 {
1866   ClutterMainContext *context;
1867   GOptionGroup *group;
1868
1869   clutter_base_init ();
1870
1871   context = _clutter_context_get_default ();
1872   context->defer_display_setup = TRUE;
1873
1874   group = clutter_get_option_group ();
1875
1876   return group;
1877 }
1878
1879 /* Note that the gobject-introspection annotations for the argc/argv
1880  * parameters do not produce the right result; however, they do
1881  * allow the common case of argc=NULL, argv=NULL to work.
1882  */
1883
1884 /**
1885  * clutter_init_with_args:
1886  * @argc: (inout): a pointer to the number of command line arguments
1887  * @argv: (array length=argc) (inout) (allow-none): a pointer to the array
1888  *   of command line arguments
1889  * @parameter_string: (allow-none): a string which is displayed in the
1890  *   first line of <option>--help</option> output, after
1891  *   <literal><replaceable>programname</replaceable> [OPTION...]</literal>
1892  * @entries: (allow-none): a %NULL terminated array of #GOptionEntry<!-- -->s
1893  *   describing the options of your program
1894  * @translation_domain: (allow-none): a translation domain to use for
1895  *   translating the <option>--help</option> output for the options in
1896  *   @entries with gettext(), or %NULL
1897  * @error: (allow-none): a return location for a #GError
1898  *
1899  * This function does the same work as clutter_init(). Additionally,
1900  * it allows you to add your own command line options, and it
1901  * automatically generates nicely formatted <option>--help</option>
1902  * output. Note that your program will be terminated after writing
1903  * out the help output. Also note that, in case of error, the
1904  * error message will be placed inside @error instead of being
1905  * printed on the display.
1906  *
1907  * Just like clutter_init(), if this function returns an error code then
1908  * any subsequent call to any other Clutter API will result in undefined
1909  * behaviour - including segmentation faults.
1910  *
1911  * Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully
1912  *   initialised, or other values or #ClutterInitError in case of
1913  *   error.
1914  *
1915  * Since: 0.2
1916  */
1917 ClutterInitError
1918 clutter_init_with_args (int            *argc,
1919                         char         ***argv,
1920                         const char     *parameter_string,
1921                         GOptionEntry   *entries,
1922                         const char     *translation_domain,
1923                         GError        **error)
1924 {
1925   GOptionContext *context;
1926   GOptionGroup *group;
1927   gboolean res;
1928   ClutterMainContext *ctx;
1929
1930   if (clutter_is_initialized)
1931     return CLUTTER_INIT_SUCCESS;
1932
1933   clutter_base_init ();
1934
1935   ctx = _clutter_context_get_default ();
1936
1937   if (!ctx->defer_display_setup)
1938     {
1939 #if 0
1940       if (argc && *argc > 0 && *argv)
1941         g_set_prgname ((*argv)[0]);
1942 #endif
1943
1944       context = g_option_context_new (parameter_string);
1945
1946       group = clutter_get_option_group ();
1947       g_option_context_add_group (context, group);
1948
1949       group = cogl_get_option_group ();
1950       g_option_context_add_group (context, group);
1951
1952       /* Note: That due to the implementation details of glib's goption
1953        * parsing; cogl and uprof will not actually have there arguments
1954        * parsed before the post_parse_hook is called! */
1955 #ifdef CLUTTER_ENABLE_PROFILE
1956       group = uprof_get_option_group ();
1957       g_option_context_add_group (context, group);
1958 #endif
1959
1960       if (entries)
1961         g_option_context_add_main_entries (context, entries, translation_domain);
1962
1963       res = g_option_context_parse (context, argc, argv, error);
1964       g_option_context_free (context);
1965
1966       /* if res is FALSE, the error is filled for
1967        * us by g_option_context_parse()
1968        */
1969       if (!res)
1970         {
1971           /* if there has been an error in the initialization, the
1972            * error id will be preserved inside the GError code
1973            */
1974           if (error && *error)
1975             return (*error)->code;
1976           else
1977             return CLUTTER_INIT_ERROR_INTERNAL;
1978         }
1979
1980       return CLUTTER_INIT_SUCCESS;
1981     }
1982   else
1983     return clutter_init_real (error);
1984 }
1985
1986 static gboolean
1987 clutter_parse_args (int      *argc,
1988                     char   ***argv,
1989                     GError  **error)
1990 {
1991   GOptionContext *option_context;
1992   GOptionGroup *clutter_group, *cogl_group;
1993 #ifdef CLUTTER_ENABLE_PROFILE
1994   GOptionGroup *uprof_group;
1995 #endif
1996   GError *internal_error = NULL;
1997   gboolean ret = TRUE;
1998
1999   if (clutter_is_initialized)
2000     return TRUE;
2001
2002   option_context = g_option_context_new (NULL);
2003   g_option_context_set_ignore_unknown_options (option_context, TRUE);
2004   g_option_context_set_help_enabled (option_context, FALSE);
2005
2006   /* Initiate any command line options from the backend */
2007   clutter_group = clutter_get_option_group ();
2008   g_option_context_set_main_group (option_context, clutter_group);
2009
2010   cogl_group = cogl_get_option_group ();
2011   g_option_context_add_group (option_context, cogl_group);
2012
2013 #ifdef CLUTTER_ENABLE_PROFILE
2014   uprof_group = uprof_get_option_group ();
2015   g_option_context_add_group (option_context, uprof_group);
2016 #endif
2017
2018   if (!g_option_context_parse (option_context, argc, argv, &internal_error))
2019     {
2020       g_propagate_error (error, internal_error);
2021       ret = FALSE;
2022     }
2023
2024   g_option_context_free (option_context);
2025
2026   return ret;
2027 }
2028
2029 /**
2030  * clutter_init:
2031  * @argc: (inout): The number of arguments in @argv
2032  * @argv: (array length=argc) (inout) (allow-none): A pointer to an array
2033  *   of arguments.
2034  *
2035  * Initialises everything needed to operate with Clutter and parses some
2036  * standard command line options; @argc and @argv are adjusted accordingly
2037  * so your own code will never see those standard arguments.
2038  *
2039  * It is safe to call this function multiple times.
2040  *
2041  * <note>This function will not abort in case of errors during
2042  * initialization; clutter_init() will print out the error message on
2043  * stderr, and will return an error code. It is up to the application
2044  * code to handle this case. If you need to display the error message
2045  * yourself, you can use clutter_init_with_args(), which takes a #GError
2046  * pointer.</note>
2047  *
2048  * If this function fails, and returns an error code, any subsequent
2049  * Clutter API will have undefined behaviour - including segmentation
2050  * faults and assertion failures. Make sure to handle the returned
2051  * #ClutterInitError enumeration value.
2052  *
2053  * Return value: a #ClutterInitError value
2054  */
2055 ClutterInitError
2056 clutter_init (int    *argc,
2057               char ***argv)
2058 {
2059   ClutterMainContext *ctx;
2060   GError *error = NULL;
2061   ClutterInitError res;
2062
2063   if (clutter_is_initialized)
2064     return CLUTTER_INIT_SUCCESS;
2065
2066   clutter_base_init ();
2067
2068   ctx = _clutter_context_get_default ();
2069
2070   if (!ctx->defer_display_setup)
2071     {
2072 #if 0
2073       if (argc && *argc > 0 && *argv)
2074         g_set_prgname ((*argv)[0]);
2075 #endif
2076
2077       /* parse_args will trigger backend creation and things like
2078        * DISPLAY connection etc.
2079        */
2080       if (!clutter_parse_args (argc, argv, &error))
2081         {
2082           g_critical ("Unable to initialize Clutter: %s", error->message);
2083           g_error_free (error);
2084
2085           res = CLUTTER_INIT_ERROR_INTERNAL;
2086         }
2087       else
2088         res = CLUTTER_INIT_SUCCESS;
2089     }
2090   else
2091     {
2092       res = clutter_init_real (&error);
2093       if (error != NULL)
2094         {
2095           g_critical ("Unable to initialize Clutter: %s", error->message);
2096           g_error_free (error);
2097         }
2098     }
2099
2100   return res;
2101 }
2102
2103 gboolean
2104 _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2105                                       GValue                *return_accu,
2106                                       const GValue          *handler_return,
2107                                       gpointer               dummy)
2108 {
2109   gboolean continue_emission;
2110   gboolean signal_handled;
2111
2112   signal_handled = g_value_get_boolean (handler_return);
2113   g_value_set_boolean (return_accu, signal_handled);
2114   continue_emission = !signal_handled;
2115
2116   return continue_emission;
2117 }
2118
2119 static void
2120 event_click_count_generate (ClutterEvent *event)
2121 {
2122   /* multiple button click detection */
2123   static gint    click_count            = 0;
2124   static gint    previous_x             = -1;
2125   static gint    previous_y             = -1;
2126   static guint32 previous_time          = 0;
2127   static gint    previous_button_number = -1;
2128
2129   ClutterInputDevice *device = NULL;
2130   ClutterSettings *settings;
2131   guint double_click_time;
2132   guint double_click_distance;
2133
2134   settings = clutter_settings_get_default ();
2135
2136   g_object_get (settings,
2137                 "double-click-distance", &double_click_distance,
2138                 "double-click-time", &double_click_time,
2139                 NULL);
2140
2141   device = clutter_event_get_device (event);
2142   if (device != NULL)
2143     {
2144       click_count = device->click_count;
2145       previous_x = device->previous_x;
2146       previous_y = device->previous_y;
2147       previous_time = device->previous_time;
2148       previous_button_number = device->previous_button_number;
2149
2150       CLUTTER_NOTE (EVENT,
2151                     "Restoring previous click count:%d (device:%d, time:%u)",
2152                     click_count,
2153                     clutter_input_device_get_device_id (device),
2154                     previous_time);
2155     }
2156   else
2157     {
2158       CLUTTER_NOTE (EVENT,
2159                     "Restoring previous click count:%d (time:%u)",
2160                     click_count,
2161                     previous_time);
2162     }
2163
2164   switch (clutter_event_type (event))
2165     {
2166       case CLUTTER_BUTTON_PRESS:
2167         /* check if we are in time and within distance to increment an
2168          * existing click count
2169          */
2170         if (event->button.button == previous_button_number &&
2171             event->button.time < (previous_time + double_click_time) &&
2172             (ABS (event->button.x - previous_x) <= double_click_distance) &&
2173             (ABS (event->button.y - previous_y) <= double_click_distance))
2174           {
2175             CLUTTER_NOTE (EVENT, "Increase click count (button: %d, time: %u)",
2176                           event->button.button,
2177                           event->button.time);
2178
2179             click_count += 1;
2180           }
2181         else /* start a new click count*/
2182           {
2183             CLUTTER_NOTE (EVENT, "Reset click count (button: %d, time: %u)",
2184                           event->button.button,
2185                           event->button.time);
2186
2187             click_count = 1;
2188             previous_button_number = event->button.button;
2189           }
2190
2191         previous_x = event->button.x;
2192         previous_y = event->button.y;
2193         previous_time = event->button.time;
2194
2195         /* fallthrough */
2196       case CLUTTER_BUTTON_RELEASE:
2197         event->button.click_count = click_count;
2198         break;
2199
2200       default:
2201         g_assert_not_reached ();
2202         break;
2203     }
2204
2205   if (event->type == CLUTTER_BUTTON_PRESS && device != NULL)
2206     {
2207       CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%d, time:%u)",
2208                     click_count,
2209                     clutter_input_device_get_device_id (device),
2210                     previous_time);
2211
2212       device->click_count = click_count;
2213       device->previous_x = previous_x;
2214       device->previous_y = previous_y;
2215       device->previous_time = previous_time;
2216       device->previous_button_number = previous_button_number;
2217     }
2218 }
2219
2220 static inline void
2221 emit_event (ClutterEvent *event,
2222             gboolean      is_key_event)
2223 {
2224   static gboolean      lock = FALSE;
2225
2226   GPtrArray *event_tree = NULL;
2227   ClutterActor *actor;
2228   gint i = 0;
2229
2230   if (event->any.source == NULL)
2231     {
2232       CLUTTER_NOTE (EVENT, "No source set, discarding event");
2233       return;
2234     }
2235
2236   /* reentrancy check */
2237   if (lock != FALSE)
2238     {
2239       g_warning ("Tried emitting event during event delivery, bailing out.");
2240       return;
2241     }
2242
2243   lock = TRUE;
2244
2245   event_tree = g_ptr_array_sized_new (64);
2246
2247   actor = event->any.source;
2248
2249   /* Build 'tree' of emitters for the event */
2250   while (actor)
2251     {
2252       ClutterActor *parent;
2253
2254       parent = clutter_actor_get_parent (actor);
2255
2256       if (clutter_actor_get_reactive (actor) ||
2257           parent == NULL ||         /* stage gets all events */
2258           is_key_event)             /* keyboard events are always emitted */
2259         {
2260           g_ptr_array_add (event_tree, g_object_ref (actor));
2261         }
2262
2263       actor = parent;
2264     }
2265
2266   /* Capture */
2267   for (i = event_tree->len - 1; i >= 0; i--)
2268     if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, TRUE))
2269       goto done;
2270
2271   /* Bubble */
2272   for (i = 0; i < event_tree->len; i++)
2273     if (clutter_actor_event (g_ptr_array_index (event_tree, i), event, FALSE))
2274       goto done;
2275
2276 done:
2277   for (i = 0; i < event_tree->len; i++)
2278     g_object_unref (g_ptr_array_index (event_tree, i));
2279
2280   g_ptr_array_free (event_tree, TRUE);
2281
2282   lock = FALSE;
2283 }
2284
2285 /*
2286  * Emits a pointer event after having prepared the event for delivery (setting
2287  * source, computing click_count, generating enter/leave etc.).
2288  */
2289
2290 static inline void
2291 emit_pointer_event (ClutterEvent       *event,
2292                     ClutterInputDevice *device)
2293 {
2294   ClutterMainContext *context = _clutter_context_get_default ();
2295
2296   if (context->pointer_grab_actor == NULL &&
2297       (device == NULL || device->pointer_grab_actor == NULL))
2298     {
2299       /* no grab, time to capture and bubble */
2300       emit_event (event, FALSE);
2301     }
2302   else
2303     {
2304       if (context->pointer_grab_actor != NULL)
2305         {
2306           /* global grab */
2307           clutter_actor_event (context->pointer_grab_actor, event, FALSE);
2308         }
2309       else if (device != NULL && device->pointer_grab_actor != NULL)
2310         {
2311           /* per device grab */
2312           clutter_actor_event (device->pointer_grab_actor, event, FALSE);
2313         }
2314     }
2315 }
2316
2317 static inline void
2318 emit_keyboard_event (ClutterEvent       *event,
2319                      ClutterInputDevice *device)
2320 {
2321   ClutterMainContext *context = _clutter_context_get_default ();
2322
2323   if (context->keyboard_grab_actor == NULL &&
2324       (device == NULL || device->keyboard_grab_actor == NULL))
2325     {
2326       emit_event (event, TRUE);
2327     }
2328   else
2329     {
2330       if (context->keyboard_grab_actor != NULL)
2331         {
2332           clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
2333         }
2334       else if (device != NULL && device->keyboard_grab_actor != NULL)
2335         {
2336           clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
2337         }
2338     }
2339 }
2340
2341 static gboolean
2342 is_off_stage (ClutterActor *stage,
2343               gfloat        x,
2344               gfloat        y)
2345 {
2346   gfloat width, height;
2347
2348   clutter_actor_get_size (stage, &width, &height);
2349
2350   return (x < 0 ||
2351           y < 0 ||
2352           x >= width ||
2353           y >= height);
2354 }
2355
2356 /**
2357  * clutter_do_event:
2358  * @event: a #ClutterEvent.
2359  *
2360  * Processes an event.
2361  *
2362  * The @event must be a valid #ClutterEvent and have a #ClutterStage
2363  * associated to it.
2364  *
2365  * This function is only useful when embedding Clutter inside another
2366  * toolkit, and it should never be called by applications.
2367  *
2368  * Since: 0.4
2369  */
2370 void
2371 clutter_do_event (ClutterEvent *event)
2372 {
2373   /* we need the stage for the event */
2374   if (event->any.stage == NULL)
2375     {
2376       g_warning ("%s: Event does not have a stage: discarding.", G_STRFUNC);
2377       return;
2378     }
2379
2380   /* stages in destruction do not process events */
2381   if (CLUTTER_ACTOR_IN_DESTRUCTION (event->any.stage))
2382     return;
2383
2384   /* Instead of processing events when received, we queue them up to
2385    * handle per-frame before animations, layout, and drawing.
2386    *
2387    * This gives us the chance to reliably compress motion events
2388    * because we've "looked ahead" and know all motion events that
2389    * will occur before drawing the frame.
2390    */
2391   _clutter_stage_queue_event (event->any.stage, event);
2392 }
2393
2394 static void
2395 _clutter_process_event_details (ClutterActor        *stage,
2396                                 ClutterMainContext  *context,
2397                                 ClutterEvent        *event)
2398 {
2399   ClutterInputDevice *device = NULL;
2400
2401   device = clutter_event_get_device (event);
2402
2403   switch (event->type)
2404     {
2405       case CLUTTER_NOTHING:
2406         event->any.source = stage;
2407         break;
2408
2409       case CLUTTER_KEY_PRESS:
2410       case CLUTTER_KEY_RELEASE:
2411         {
2412           ClutterActor *actor = NULL;
2413
2414           /* check that we're not a synthetic event with source set */
2415           if (event->any.source == NULL)
2416             {
2417               actor = clutter_stage_get_key_focus (CLUTTER_STAGE (stage));
2418               event->any.source = actor;
2419               if (G_UNLIKELY (actor == NULL))
2420                 {
2421                   g_warning ("No key focus set, discarding");
2422                   return;
2423                 }
2424             }
2425
2426           emit_keyboard_event (event, device);
2427         }
2428         break;
2429
2430       case CLUTTER_ENTER:
2431         /* if we're entering from outside the stage we need
2432          * to check whether the pointer is actually on another
2433          * actor, and emit an additional pointer event
2434          */
2435         if (event->any.source == stage &&
2436             event->crossing.related == NULL)
2437           {
2438             ClutterActor *actor = NULL;
2439
2440             emit_pointer_event (event, device);
2441
2442             actor = _clutter_input_device_update (device, FALSE);
2443             if (actor != stage)
2444               {
2445                 ClutterEvent *crossing;
2446
2447                 /* we emit the exact same event on the actor */
2448                 crossing = clutter_event_copy (event);
2449                 crossing->crossing.related = stage;
2450                 crossing->crossing.source = actor;
2451
2452                 emit_pointer_event (crossing, device);
2453                 clutter_event_free (crossing);
2454               }
2455           }
2456         else
2457           emit_pointer_event (event, device);
2458         break;
2459
2460       case CLUTTER_LEAVE:
2461         /* same as CLUTTER_ENTER above: when leaving the stage
2462          * we need to also emit a CLUTTER_LEAVE event on the
2463          * actor currently underneath the device, unless it's the
2464          * stage
2465          */
2466         if (event->any.source == stage &&
2467             event->crossing.related == NULL &&
2468             device->cursor_actor != stage)
2469           {
2470             ClutterEvent *crossing;
2471
2472             crossing = clutter_event_copy (event);
2473             crossing->crossing.related = stage;
2474             crossing->crossing.source = device->cursor_actor;
2475
2476             emit_pointer_event (crossing, device);
2477             clutter_event_free (crossing);
2478           }
2479         emit_pointer_event (event, device);
2480         break;
2481
2482       case CLUTTER_DESTROY_NOTIFY:
2483       case CLUTTER_DELETE:
2484         event->any.source = stage;
2485         /* the stage did not handle the event, so we just quit */
2486         clutter_stage_event (CLUTTER_STAGE (stage), event);
2487         break;
2488
2489       case CLUTTER_MOTION:
2490         /* only the stage gets motion events if they are enabled */
2491         if (!clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)) &&
2492             event->any.source == NULL)
2493           {
2494             /* Only stage gets motion events */
2495             event->any.source = stage;
2496
2497             /* global grabs */
2498             if (context->pointer_grab_actor != NULL)
2499               {
2500                 clutter_actor_event (context->pointer_grab_actor,
2501                                      event,
2502                                      FALSE);
2503                 break;
2504               }
2505             else if (device != NULL && device->pointer_grab_actor != NULL)
2506               {
2507                 clutter_actor_event (device->pointer_grab_actor,
2508                                      event,
2509                                      FALSE);
2510                 break;
2511               }
2512
2513             /* Trigger handlers on stage in both capture .. */
2514             if (!clutter_actor_event (stage, event, TRUE))
2515               {
2516                 /* and bubbling phase */
2517                 clutter_actor_event (stage, event, FALSE);
2518               }
2519             break;
2520           }
2521
2522       /* fallthrough from motion */
2523       case CLUTTER_BUTTON_PRESS:
2524       case CLUTTER_BUTTON_RELEASE:
2525       case CLUTTER_SCROLL:
2526         {
2527           ClutterActor *actor;
2528           gfloat x, y;
2529
2530           clutter_event_get_coords (event, &x, &y);
2531
2532           /* Only do a pick to find the source if source is not already set
2533            * (as it could be in a synthetic event)
2534            */
2535           if (event->any.source == NULL)
2536             {
2537               /* emulate X11 the implicit soft grab; the implicit soft grab
2538                * keeps relaying motion events when the stage is left with a
2539                * pointer button pressed. since this is what happens when we
2540                * disable per-actor motion events we need to maintain the same
2541                * behaviour when the per-actor motion events are enabled as
2542                * well
2543                */
2544               if (is_off_stage (stage, x, y))
2545                 {
2546                   if (event->type == CLUTTER_BUTTON_RELEASE)
2547                     {
2548                       CLUTTER_NOTE (EVENT,
2549                                     "Release off stage received at %.2f, %.2f",
2550                                     x, y);
2551
2552                       event->button.source = stage;
2553                       event->button.click_count = 1;
2554
2555                       emit_pointer_event (event, device);
2556                     }
2557                   else if (event->type == CLUTTER_MOTION)
2558                     {
2559                       CLUTTER_NOTE (EVENT,
2560                                     "Motion off stage received at %.2f, %2.f",
2561                                     x, y);
2562
2563                       event->motion.source = stage;
2564
2565                       emit_pointer_event (event, device);
2566                     }
2567
2568                   break;
2569                 }
2570
2571               /* if the backend provides a device then we should
2572                * already have everything we need to update it and
2573                * get the actor underneath
2574                */
2575               if (device != NULL)
2576                 actor = _clutter_input_device_update (device, TRUE);
2577               else
2578                 {
2579                   CLUTTER_NOTE (EVENT, "No device found: picking");
2580
2581                   actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
2582                                                   x, y,
2583                                                   CLUTTER_PICK_REACTIVE);
2584                 }
2585
2586               if (actor == NULL)
2587                 break;
2588
2589               event->any.source = actor;
2590             }
2591           else
2592             {
2593               /* use the source already set in the synthetic event */
2594               actor = event->any.source;
2595             }
2596
2597           CLUTTER_NOTE (EVENT,
2598                         "Reactive event received at %.2f, %.2f - actor: %p",
2599                         x, y,
2600                         actor);
2601
2602           /* button presses and releases need a click count */
2603           if (event->type == CLUTTER_BUTTON_PRESS ||
2604               event->type == CLUTTER_BUTTON_RELEASE)
2605             {
2606               /* Generate click count */
2607               event_click_count_generate (event);
2608             }
2609
2610           emit_pointer_event (event, device);
2611           break;
2612         }
2613
2614       case CLUTTER_TOUCH_BEGIN:
2615       case CLUTTER_TOUCH_UPDATE:
2616       case CLUTTER_TOUCH_END:
2617         {
2618           ClutterActor *actor;
2619           gfloat x, y;
2620
2621           clutter_event_get_coords (event, &x, &y);
2622
2623           /* Only do a pick to find the source if source is not already set
2624            * (as it could be in a synthetic event)
2625            */
2626           if (event->any.source == NULL)
2627             {
2628               actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
2629                                               x, y,
2630                                               CLUTTER_PICK_REACTIVE);
2631               if (actor == NULL)
2632                 break;
2633
2634               event->any.source = actor;
2635             }
2636           else
2637             {
2638               /* use the source already set in the synthetic event */
2639               actor = event->any.source;
2640             }
2641
2642           CLUTTER_NOTE (EVENT,
2643                         "Reactive event received at %.2f, %.2f - actor: %p",
2644                         x, y,
2645                         actor);
2646
2647           emit_pointer_event (event, device);
2648           break;
2649         }
2650
2651       case CLUTTER_TOUCH_CANCEL:
2652         break;
2653
2654       case CLUTTER_STAGE_STATE:
2655         /* fullscreen / focus - forward to stage */
2656         event->any.source = stage;
2657         clutter_stage_event (CLUTTER_STAGE (stage), event);
2658         break;
2659
2660       case CLUTTER_CLIENT_MESSAGE:
2661         break;
2662
2663       case CLUTTER_EVENT_LAST:
2664         break;
2665     }
2666 }
2667
2668 /*
2669  * _clutter_process_event
2670  * @event: a #ClutterEvent.
2671  *
2672  * Does the actual work of processing an event that was queued earlier
2673  * out of clutter_do_event().
2674  */
2675 void
2676 _clutter_process_event (ClutterEvent *event)
2677 {
2678   ClutterMainContext *context;
2679   ClutterActor *stage;
2680
2681   context = _clutter_context_get_default ();
2682
2683   stage = CLUTTER_ACTOR (event->any.stage);
2684   if (stage == NULL)
2685     return;
2686
2687   CLUTTER_NOTE (EVENT, "Event received");
2688
2689   context->last_event_time = clutter_event_get_time (event);
2690
2691   context->current_event = event;
2692   _clutter_process_event_details (stage, context, event);
2693   context->current_event = NULL;
2694 }
2695
2696 /**
2697  * clutter_get_actor_by_gid:
2698  * @id_: a #ClutterActor unique id.
2699  *
2700  * Retrieves the #ClutterActor with @id_.
2701  *
2702  * Return value: (transfer none): the actor with the passed id or %NULL.
2703  *   The returned actor does not have its reference count increased.
2704  *
2705  * Since: 0.6
2706  *
2707  * Deprecated: 1.8: The id is not used any longer.
2708  */
2709 ClutterActor *
2710 clutter_get_actor_by_gid (guint32 id_)
2711 {
2712   return _clutter_get_actor_by_id (NULL, id_);
2713 }
2714
2715 void
2716 clutter_base_init (void)
2717 {
2718   static gboolean initialised = FALSE;
2719
2720   if (!initialised)
2721     {
2722       initialised = TRUE;
2723
2724       bindtextdomain (GETTEXT_PACKAGE, CLUTTER_LOCALEDIR);
2725       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2726
2727       /* initialise GLib type system */
2728       g_type_init ();
2729
2730       /* initialise the Big Clutter Lockâ„¢ if necessary */
2731       clutter_threads_init_default ();
2732     }
2733 }
2734
2735 /**
2736  * clutter_get_default_frame_rate:
2737  *
2738  * Retrieves the default frame rate. See clutter_set_default_frame_rate().
2739  *
2740  * Return value: the default frame rate
2741  *
2742  * Since: 0.6
2743  */
2744 guint
2745 clutter_get_default_frame_rate (void)
2746 {
2747   ClutterMainContext *context;
2748
2749   context = _clutter_context_get_default ();
2750
2751   return context->frame_rate;
2752 }
2753
2754 /**
2755  * clutter_set_default_frame_rate:
2756  * @frames_per_sec: the new default frame rate
2757  *
2758  * Sets the default frame rate. This frame rate will be used to limit
2759  * the number of frames drawn if Clutter is not able to synchronize
2760  * with the vertical refresh rate of the display. When synchronization
2761  * is possible, this value is ignored.
2762  *
2763  * Since: 0.6
2764  *
2765  * Deprecated: 1.10: This function does not do anything any more.
2766  */
2767 void
2768 clutter_set_default_frame_rate (guint frames_per_sec)
2769 {
2770 }
2771
2772 static void
2773 on_grab_actor_destroy (ClutterActor       *actor,
2774                        ClutterInputDevice *device)
2775 {
2776   if (device == NULL)
2777     {
2778       ClutterMainContext *context = _clutter_context_get_default ();
2779
2780       if (context->pointer_grab_actor == actor)
2781         clutter_ungrab_pointer ();
2782
2783       if (context->keyboard_grab_actor == actor)
2784         clutter_ungrab_keyboard ();
2785
2786       return;
2787     }
2788
2789   switch (device->device_type)
2790     {
2791     case CLUTTER_POINTER_DEVICE:
2792       device->pointer_grab_actor = NULL;
2793       break;
2794
2795     case CLUTTER_KEYBOARD_DEVICE:
2796       device->keyboard_grab_actor = NULL;
2797       break;
2798
2799     default:
2800       g_assert_not_reached ();
2801     }
2802 }
2803
2804 /**
2805  * clutter_grab_pointer:
2806  * @actor: a #ClutterActor
2807  *
2808  * Grabs pointer events, after the grab is done all pointer related events
2809  * (press, motion, release, enter, leave and scroll) are delivered to this
2810  * actor directly without passing through both capture and bubble phases of
2811  * the event delivery chain. The source set in the event will be the actor
2812  * that would have received the event if the pointer grab was not in effect.
2813  *
2814  * <note><para>Grabs completely override the entire event delivery chain
2815  * done by Clutter. Pointer grabs should only be used as a last resource;
2816  * using the #ClutterActor::captured-event signal should always be the
2817  * preferred way to intercept event delivery to reactive actors.</para></note>
2818  *
2819  * This function should rarely be used.
2820  *
2821  * If a grab is required, you are strongly encouraged to use a specific
2822  * input device by calling clutter_input_device_grab().
2823  *
2824  * Since: 0.6
2825  */
2826 void
2827 clutter_grab_pointer (ClutterActor *actor)
2828 {
2829   ClutterMainContext *context;
2830
2831   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2832
2833   context = _clutter_context_get_default ();
2834
2835   if (context->pointer_grab_actor == actor)
2836     return;
2837
2838   if (context->pointer_grab_actor != NULL)
2839     {
2840       g_signal_handlers_disconnect_by_func (context->pointer_grab_actor,
2841                                             G_CALLBACK (on_grab_actor_destroy),
2842                                             NULL);
2843       context->pointer_grab_actor = NULL;
2844     }
2845
2846   if (actor != NULL)
2847     {
2848       context->pointer_grab_actor = actor;
2849
2850       g_signal_connect (context->pointer_grab_actor, "destroy",
2851                         G_CALLBACK (on_grab_actor_destroy),
2852                         NULL);
2853     }
2854 }
2855
2856 /**
2857  * clutter_input_device_grab:
2858  * @device: a #ClutterInputDevice
2859  * @actor: a #ClutterActor
2860  *
2861  * Acquires a grab on @actor for the given @device.
2862  *
2863  * Any event coming from @device will be delivered to @actor, bypassing
2864  * the usual event delivery mechanism, until the grab is released by
2865  * calling clutter_input_device_ungrab().
2866  *
2867  * The grab is client-side: even if the windowing system used by the Clutter
2868  * backend has the concept of "device grabs", Clutter will not use them.
2869  *
2870  * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE and
2871  * %CLUTTER_KEYBOARD_DEVICE can hold a grab.
2872  *
2873  * Since: 1.10
2874  */
2875 void
2876 clutter_input_device_grab (ClutterInputDevice *device,
2877                            ClutterActor       *actor)
2878 {
2879   ClutterActor **grab_actor;
2880
2881   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2882   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
2883
2884   switch (device->device_type)
2885     {
2886     case CLUTTER_POINTER_DEVICE:
2887       grab_actor = &(device->pointer_grab_actor);
2888       break;
2889
2890     case CLUTTER_KEYBOARD_DEVICE:
2891       grab_actor = &(device->keyboard_grab_actor);
2892       break;
2893
2894     default:
2895       g_critical ("Only pointer and keyboard devices can grab an actor");
2896       return;
2897     }
2898
2899   if (*grab_actor != NULL)
2900     {
2901       g_signal_handlers_disconnect_by_func (*grab_actor,
2902                                             G_CALLBACK (on_grab_actor_destroy),
2903                                             device);
2904     }
2905
2906   *grab_actor = actor;
2907
2908   g_signal_connect (*grab_actor,
2909                     "destroy",
2910                     G_CALLBACK (on_grab_actor_destroy),
2911                     device);
2912 }
2913
2914 /**
2915  * clutter_input_device_ungrab:
2916  * @device: a #ClutterInputDevice
2917  *
2918  * Releases the grab on the @device, if one is in place.
2919  *
2920  * Since: 1.10
2921  */
2922 void
2923 clutter_input_device_ungrab (ClutterInputDevice *device)
2924 {
2925   ClutterActor **grab_actor;
2926
2927   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2928
2929   switch (device->device_type)
2930     {
2931     case CLUTTER_POINTER_DEVICE:
2932       grab_actor = &(device->pointer_grab_actor);
2933       break;
2934
2935     case CLUTTER_KEYBOARD_DEVICE:
2936       grab_actor = &(device->keyboard_grab_actor);
2937       break;
2938
2939     default:
2940       return;
2941     }
2942
2943   if (*grab_actor == NULL)
2944     return;
2945
2946   g_signal_handlers_disconnect_by_func (*grab_actor,
2947                                         G_CALLBACK (on_grab_actor_destroy),
2948                                         device);
2949
2950   *grab_actor = NULL;
2951 }
2952
2953 /**
2954  * clutter_input_device_get_grabbed_actor:
2955  * @device: a #ClutterInputDevice
2956  *
2957  * Retrieves a pointer to the #ClutterActor currently grabbing all
2958  * the events coming from @device.
2959  *
2960  * Return value: (transfer none): a #ClutterActor, or %NULL
2961  *
2962  * Since: 1.10
2963  */
2964 ClutterActor *
2965 clutter_input_device_get_grabbed_actor (ClutterInputDevice *device)
2966 {
2967   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2968
2969   switch (device->device_type)
2970     {
2971     case CLUTTER_POINTER_DEVICE:
2972       return device->pointer_grab_actor;
2973
2974     case CLUTTER_KEYBOARD_DEVICE:
2975       return device->keyboard_grab_actor;
2976
2977     default:
2978       g_critical ("Only pointer and keyboard devices can grab an actor");
2979     }
2980
2981   return NULL;
2982 }
2983
2984 /**
2985  * clutter_grab_pointer_for_device:
2986  * @actor: a #ClutterActor
2987  * @id_: a device id, or -1
2988  *
2989  * Grabs all the pointer events coming from the device @id for @actor.
2990  *
2991  * If @id is -1 then this function is equivalent to clutter_grab_pointer().
2992  *
2993  * Since: 0.8
2994  *
2995  * Deprecated: 1.10: Use clutter_input_device_grab() instead.
2996  */
2997 void
2998 clutter_grab_pointer_for_device (ClutterActor *actor,
2999                                  gint          id_)
3000 {
3001   ClutterDeviceManager *manager;
3002   ClutterInputDevice *dev;
3003
3004   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
3005
3006   /* essentially a global grab */
3007   if (id_ == -1)
3008     {
3009       if (actor == NULL)
3010         clutter_ungrab_pointer ();
3011       else
3012         clutter_grab_pointer (actor);
3013
3014       return;
3015     }
3016
3017   manager = clutter_device_manager_get_default ();
3018   if (manager == NULL)
3019     return;
3020
3021   dev = clutter_device_manager_get_device (manager, id_);
3022   if (dev == NULL)
3023     return;
3024
3025   if (dev->device_type != CLUTTER_POINTER_DEVICE)
3026     return;
3027
3028   if (actor == NULL)
3029     clutter_input_device_ungrab (dev);
3030   else
3031     clutter_input_device_grab (dev, actor);
3032 }
3033
3034
3035 /**
3036  * clutter_ungrab_pointer:
3037  *
3038  * Removes an existing grab of the pointer.
3039  *
3040  * Since: 0.6
3041  */
3042 void
3043 clutter_ungrab_pointer (void)
3044 {
3045   clutter_grab_pointer (NULL);
3046 }
3047
3048 /**
3049  * clutter_ungrab_pointer_for_device:
3050  * @id_: a device id
3051  *
3052  * Removes an existing grab of the pointer events for device @id_.
3053  *
3054  * Since: 0.8
3055  *
3056  * Deprecated: 1.10: Use clutter_input_device_ungrab() instead.
3057  */
3058 void
3059 clutter_ungrab_pointer_for_device (gint id_)
3060 {
3061   ClutterDeviceManager *manager;
3062   ClutterInputDevice *device;
3063
3064   manager = clutter_device_manager_get_default ();
3065   if (manager == NULL)
3066     return;
3067
3068   device = clutter_device_manager_get_device (manager, id_);
3069   if (device != NULL)
3070     clutter_input_device_ungrab (device);
3071 }
3072
3073
3074 /**
3075  * clutter_get_pointer_grab:
3076  *
3077  * Queries the current pointer grab of clutter.
3078  *
3079  * Return value: (transfer none): the actor currently holding the pointer grab, or NULL if there is no grab.
3080  *
3081  * Since: 0.6
3082  */
3083 ClutterActor *
3084 clutter_get_pointer_grab (void)
3085 {
3086   ClutterMainContext *context;
3087   context = _clutter_context_get_default ();
3088
3089   return context->pointer_grab_actor;
3090 }
3091
3092
3093 /**
3094  * clutter_grab_keyboard:
3095  * @actor: a #ClutterActor
3096  *
3097  * Grabs keyboard events, after the grab is done keyboard
3098  * events (#ClutterActor::key-press-event and #ClutterActor::key-release-event)
3099  * are delivered to this actor directly. The source set in the event will be
3100  * the actor that would have received the event if the keyboard grab was not
3101  * in effect.
3102  *
3103  * Like pointer grabs, keyboard grabs should only be used as a last
3104  * resource.
3105  *
3106  * See also clutter_stage_set_key_focus() and clutter_actor_grab_key_focus()
3107  * to perform a "soft" key grab and assign key focus to a specific actor.
3108  *
3109  * Since: 0.6
3110  */
3111 void
3112 clutter_grab_keyboard (ClutterActor *actor)
3113 {
3114   ClutterMainContext *context;
3115
3116   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
3117
3118   context = _clutter_context_get_default ();
3119
3120   if (context->keyboard_grab_actor == actor)
3121     return;
3122
3123   if (context->keyboard_grab_actor != NULL)
3124     {
3125       g_signal_handlers_disconnect_by_func (context->keyboard_grab_actor,
3126                                             G_CALLBACK (on_grab_actor_destroy),
3127                                             NULL);
3128       context->keyboard_grab_actor = NULL;
3129     }
3130
3131   if (actor != NULL)
3132     {
3133       context->keyboard_grab_actor = actor;
3134
3135       g_signal_connect (context->keyboard_grab_actor, "destroy",
3136                         G_CALLBACK (on_grab_actor_destroy),
3137                         NULL);
3138     }
3139 }
3140
3141 /**
3142  * clutter_ungrab_keyboard:
3143  *
3144  * Removes an existing grab of the keyboard.
3145  *
3146  * Since: 0.6
3147  */
3148 void
3149 clutter_ungrab_keyboard (void)
3150 {
3151   clutter_grab_keyboard (NULL);
3152 }
3153
3154 /**
3155  * clutter_get_keyboard_grab:
3156  *
3157  * Queries the current keyboard grab of clutter.
3158  *
3159  * Return value: (transfer none): the actor currently holding the keyboard grab, or NULL if there is no grab.
3160  *
3161  * Since: 0.6
3162  */
3163 ClutterActor *
3164 clutter_get_keyboard_grab (void)
3165 {
3166   ClutterMainContext *context;
3167
3168   context = _clutter_context_get_default ();
3169
3170   return context->keyboard_grab_actor;
3171 }
3172
3173 /**
3174  * clutter_clear_glyph_cache:
3175  *
3176  * Clears the internal cache of glyphs used by the Pango
3177  * renderer. This will free up some memory and GL texture
3178  * resources. The cache will be automatically refilled as more text is
3179  * drawn.
3180  *
3181  * Since: 0.8
3182  *
3183  * Deprecated: 1.10: Use clutter_get_font_map() and
3184  *   cogl_pango_font_map_clear_glyph_cache() instead.
3185  */
3186 void
3187 clutter_clear_glyph_cache (void)
3188 {
3189   CoglPangoFontMap *font_map;
3190
3191   font_map = clutter_context_get_pango_fontmap ();
3192   cogl_pango_font_map_clear_glyph_cache (font_map);
3193 }
3194
3195 /**
3196  * clutter_set_font_flags:
3197  * @flags: The new flags
3198  *
3199  * Sets the font quality options for subsequent text rendering
3200  * operations.
3201  *
3202  * Using mipmapped textures will improve the quality for scaled down
3203  * text but will use more texture memory.
3204  *
3205  * Enabling hinting improves text quality for static text but may
3206  * introduce some artifacts if the text is animated.
3207  *
3208  * Since: 1.0
3209  *
3210  * Deprecated: 1.10: Use clutter_backend_set_font_options() and the
3211  *   #cairo_font_option_t API.
3212  */
3213 void
3214 clutter_set_font_flags (ClutterFontFlags flags)
3215 {
3216   ClutterMainContext *context = _clutter_context_get_default ();
3217   CoglPangoFontMap *font_map;
3218   ClutterFontFlags old_flags, changed_flags;
3219   const cairo_font_options_t *font_options;
3220   cairo_font_options_t *new_font_options;
3221   cairo_hint_style_t hint_style;
3222   gboolean use_mipmapping;
3223   ClutterBackend *backend;
3224
3225   backend = clutter_get_default_backend ();
3226   font_map = clutter_context_get_pango_fontmap ();
3227   font_options = clutter_backend_get_font_options (backend);
3228   old_flags = 0;
3229
3230   if (cogl_pango_font_map_get_use_mipmapping (font_map))
3231     old_flags |= CLUTTER_FONT_MIPMAPPING;
3232
3233   hint_style = cairo_font_options_get_hint_style (font_options);
3234   if (hint_style != CAIRO_HINT_STYLE_DEFAULT &&
3235       hint_style != CAIRO_HINT_STYLE_NONE)
3236     old_flags |= CLUTTER_FONT_HINTING;
3237
3238   if (old_flags == flags)
3239     return;
3240
3241   new_font_options = cairo_font_options_copy (font_options);
3242
3243   /* Only set the font options that have actually changed so we don't
3244      override a detailed setting from the backend */
3245   changed_flags = old_flags ^ flags;
3246
3247   if ((changed_flags & CLUTTER_FONT_MIPMAPPING))
3248     {
3249       use_mipmapping = (changed_flags & CLUTTER_FONT_MIPMAPPING) != 0;
3250
3251       cogl_pango_font_map_set_use_mipmapping (font_map, use_mipmapping);
3252     }
3253
3254   if ((changed_flags & CLUTTER_FONT_HINTING))
3255     {
3256       hint_style = (flags & CLUTTER_FONT_HINTING)
3257                  ? CAIRO_HINT_STYLE_FULL
3258                  : CAIRO_HINT_STYLE_NONE;
3259
3260       cairo_font_options_set_hint_style (new_font_options, hint_style);
3261     }
3262
3263   clutter_backend_set_font_options (backend, new_font_options);
3264
3265   cairo_font_options_destroy (new_font_options);
3266
3267   /* update the default pango context, if any */
3268   if (context->pango_context != NULL)
3269     update_pango_context (backend, context->pango_context);
3270 }
3271
3272 /**
3273  * clutter_get_font_flags:
3274  *
3275  * Gets the current font flags for rendering text. See
3276  * clutter_set_font_flags().
3277  *
3278  * Return value: The font flags
3279  *
3280  * Since: 1.0
3281  *
3282  * Deprecated: 1.10: Use clutter_backend_get_font_options() and the
3283  *   #cairo_font_options_t API.
3284  */
3285 ClutterFontFlags
3286 clutter_get_font_flags (void)
3287 {
3288   CoglPangoFontMap *font_map = NULL;
3289   const cairo_font_options_t *font_options;
3290   ClutterFontFlags flags = 0;
3291   cairo_hint_style_t hint_style;
3292
3293   font_map = clutter_context_get_pango_fontmap ();
3294   if (cogl_pango_font_map_get_use_mipmapping (font_map))
3295     flags |= CLUTTER_FONT_MIPMAPPING;
3296
3297   font_options =
3298     clutter_backend_get_font_options (clutter_get_default_backend ());
3299
3300   hint_style = cairo_font_options_get_hint_style (font_options);
3301   if (hint_style != CAIRO_HINT_STYLE_DEFAULT &&
3302       hint_style != CAIRO_HINT_STYLE_NONE)
3303     flags |= CLUTTER_FONT_HINTING;
3304
3305   return flags;
3306 }
3307
3308 /**
3309  * clutter_get_input_device_for_id:
3310  * @id_: the unique id for a device
3311  *
3312  * Retrieves the #ClutterInputDevice from its @id_. This is a convenience
3313  * wrapper for clutter_device_manager_get_device() and it is functionally
3314  * equivalent to:
3315  *
3316  * |[
3317  *   ClutterDeviceManager *manager;
3318  *   ClutterInputDevice *device;
3319  *
3320  *   manager = clutter_device_manager_get_default ();
3321  *   device = clutter_device_manager_get_device (manager, id);
3322  * ]|
3323  *
3324  * Return value: (transfer none): a #ClutterInputDevice, or %NULL
3325  *
3326  * Since: 0.8
3327  *
3328  * Deprecated: 1.10: Use clutter_device_manager_get_device() instead.
3329  */
3330 ClutterInputDevice *
3331 clutter_get_input_device_for_id (gint id_)
3332 {
3333   ClutterDeviceManager *manager;
3334
3335   manager = clutter_device_manager_get_default ();
3336   if (manager == NULL)
3337     return NULL;
3338
3339   return clutter_device_manager_get_device (manager, id_);
3340 }
3341
3342 /**
3343  * clutter_get_font_map:
3344  *
3345  * Retrieves the #PangoFontMap instance used by Clutter.
3346  * You can use the global font map object with the COGL
3347  * Pango API.
3348  *
3349  * Return value: (transfer none): the #PangoFontMap instance. The returned
3350  *   value is owned by Clutter and it should never be unreferenced.
3351  *
3352  * Since: 1.0
3353  */
3354 PangoFontMap *
3355 clutter_get_font_map (void)
3356 {
3357   return PANGO_FONT_MAP (clutter_context_get_pango_fontmap ());
3358 }
3359
3360 typedef struct _ClutterRepaintFunction
3361 {
3362   guint id;
3363   ClutterRepaintFlags flags;
3364   GSourceFunc func;
3365   gpointer data;
3366   GDestroyNotify notify;
3367 } ClutterRepaintFunction;
3368
3369 /**
3370  * clutter_threads_remove_repaint_func:
3371  * @handle_id: an unsigned integer greater than zero
3372  *
3373  * Removes the repaint function with @handle_id as its id
3374  *
3375  * Since: 1.0
3376  */
3377 void
3378 clutter_threads_remove_repaint_func (guint handle_id)
3379 {
3380   ClutterRepaintFunction *repaint_func;
3381   ClutterMainContext *context;
3382   GList *l;
3383
3384   g_return_if_fail (handle_id > 0);
3385
3386   _clutter_context_lock ();
3387
3388   context = clutter_context_get_default_unlocked ();
3389   l = context->repaint_funcs;
3390   while (l != NULL)
3391     {
3392       repaint_func = l->data;
3393
3394       if (repaint_func->id == handle_id)
3395         {
3396           context->repaint_funcs =
3397             g_list_remove_link (context->repaint_funcs, l);
3398
3399           g_list_free (l);
3400
3401           if (repaint_func->notify)
3402             repaint_func->notify (repaint_func->data);
3403
3404           g_slice_free (ClutterRepaintFunction, repaint_func);
3405
3406           break;
3407         }
3408
3409       l = l->next;
3410     }
3411
3412   _clutter_context_unlock ();
3413 }
3414
3415 /**
3416  * clutter_threads_add_repaint_func:
3417  * @func: the function to be called within the paint cycle
3418  * @data: data to be passed to the function, or %NULL
3419  * @notify: function to be called when removing the repaint
3420  *    function, or %NULL
3421  *
3422  * Adds a function to be called whenever Clutter is processing a new
3423  * frame.
3424  *
3425  * If the function returns %FALSE it is automatically removed from the
3426  * list of repaint functions and will not be called again.
3427  *
3428  * This function is guaranteed to be called from within the same thread
3429  * that called clutter_main(), and while the Clutter lock is being held;
3430  * the function will be called within the main loop, so it is imperative
3431  * that it does not block, otherwise the frame time budget may be lost.
3432  *
3433  * A repaint function is useful to ensure that an update of the scenegraph
3434  * is performed before the scenegraph is repainted; for instance, uploading
3435  * a frame from a video into a #ClutterTexture. By default, a repaint
3436  * function added using this function will be invoked prior to the frame
3437  * being processed.
3438  *
3439  * Adding a repaint function does not automatically ensure that a new
3440  * frame will be queued.
3441  *
3442  * When the repaint function is removed (either because it returned %FALSE
3443  * or because clutter_threads_remove_repaint_func() has been called) the
3444  * @notify function will be called, if any is set.
3445  *
3446  * See also: clutter_threads_add_repaint_func_full()
3447  *
3448  * Return value: the ID (greater than 0) of the repaint function. You
3449  *   can use the returned integer to remove the repaint function by
3450  *   calling clutter_threads_remove_repaint_func().
3451  *
3452  * Since: 1.0
3453  */
3454 guint
3455 clutter_threads_add_repaint_func (GSourceFunc    func,
3456                                   gpointer       data,
3457                                   GDestroyNotify notify)
3458 {
3459   return clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
3460                                                 func,
3461                                                 data, notify);
3462 }
3463
3464 /**
3465  * clutter_threads_add_repaint_func_full:
3466  * @flags: flags for the repaint function
3467  * @func: the function to be called within the paint cycle
3468  * @data: data to be passed to the function, or %NULL
3469  * @notify: function to be called when removing the repaint
3470  *    function, or %NULL
3471  *
3472  * Adds a function to be called whenever Clutter is processing a new
3473  * frame.
3474  *
3475  * If the function returns %FALSE it is automatically removed from the
3476  * list of repaint functions and will not be called again.
3477  *
3478  * This function is guaranteed to be called from within the same thread
3479  * that called clutter_main(), and while the Clutter lock is being held;
3480  * the function will be called within the main loop, so it is imperative
3481  * that it does not block, otherwise the frame time budget may be lost.
3482  *
3483  * A repaint function is useful to ensure that an update of the scenegraph
3484  * is performed before the scenegraph is repainted; for instance, uploading
3485  * a frame from a video into a #ClutterTexture. The @flags passed to this
3486  * function will determine the section of the frame processing that will
3487  * result in @func being called.
3488  *
3489  * Adding a repaint function does not automatically ensure that a new
3490  * frame will be queued.
3491  *
3492  * When the repaint function is removed (either because it returned %FALSE
3493  * or because clutter_threads_remove_repaint_func() has been called) the
3494  * @notify function will be called, if any is set.
3495  *
3496  * Return value: the ID (greater than 0) of the repaint function. You
3497  *   can use the returned integer to remove the repaint function by
3498  *   calling clutter_threads_remove_repaint_func().
3499  *
3500  * Since: 1.10
3501  */
3502 guint
3503 clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
3504                                        GSourceFunc         func,
3505                                        gpointer            data,
3506                                        GDestroyNotify      notify)
3507 {
3508   ClutterMainContext *context;
3509   ClutterRepaintFunction *repaint_func;
3510
3511   g_return_val_if_fail (func != NULL, 0);
3512
3513   _clutter_context_lock ();
3514
3515   context = clutter_context_get_default_unlocked ();
3516
3517   repaint_func = g_slice_new (ClutterRepaintFunction);
3518
3519   repaint_func->id = context->last_repaint_id++;
3520
3521   /* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */
3522   repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD;
3523   repaint_func->func = func;
3524   repaint_func->data = data;
3525   repaint_func->notify = notify;
3526
3527   context->repaint_funcs = g_list_prepend (context->repaint_funcs,
3528                                            repaint_func);
3529
3530   _clutter_context_unlock ();
3531
3532   if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0)
3533     {
3534       ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
3535
3536       _clutter_master_clock_ensure_next_iteration (master_clock);
3537     }
3538
3539   return repaint_func->id;
3540 }
3541
3542 /*
3543  * _clutter_run_repaint_functions:
3544  * @flags: only run the repaint functions matching the passed flags
3545  *
3546  * Executes the repaint functions added using the
3547  * clutter_threads_add_repaint_func() function.
3548  *
3549  * Must be called with the Clutter thread lock held.
3550  */
3551 void
3552 _clutter_run_repaint_functions (ClutterRepaintFlags flags)
3553 {
3554   ClutterMainContext *context = _clutter_context_get_default ();
3555   ClutterRepaintFunction *repaint_func;
3556   GList *invoke_list, *reinvoke_list, *l;
3557
3558   if (context->repaint_funcs == NULL)
3559     return;
3560
3561   /* steal the list */
3562   invoke_list = context->repaint_funcs;
3563   context->repaint_funcs = NULL;
3564
3565   reinvoke_list = NULL;
3566
3567   /* consume the whole list while we execute the functions */
3568   while (invoke_list != NULL)
3569     {
3570       gboolean res = FALSE;
3571
3572       repaint_func = invoke_list->data;
3573
3574       l = invoke_list;
3575       invoke_list = g_list_remove_link (invoke_list, invoke_list);
3576
3577       g_list_free (l);
3578
3579       if ((repaint_func->flags & flags) != 0)
3580         res = repaint_func->func (repaint_func->data);
3581       else
3582         res = TRUE;
3583
3584       if (res)
3585         reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
3586       else
3587         {
3588           if (repaint_func->notify != NULL)
3589             repaint_func->notify (repaint_func->data);
3590
3591           g_slice_free (ClutterRepaintFunction, repaint_func);
3592         }
3593     }
3594
3595   if (context->repaint_funcs != NULL)
3596     {
3597       context->repaint_funcs = g_list_concat (context->repaint_funcs,
3598                                               g_list_reverse (reinvoke_list));
3599     }
3600   else
3601     context->repaint_funcs = g_list_reverse (reinvoke_list);
3602 }
3603
3604 /**
3605  * clutter_check_version:
3606  * @major: major version, like 1 in 1.2.3
3607  * @minor: minor version, like 2 in 1.2.3
3608  * @micro: micro version, like 3 in 1.2.3
3609  *
3610  * Run-time version check, to check the version the Clutter library
3611  * that an application is currently linked against
3612  *
3613  * This is the run-time equivalent of the compile-time %CLUTTER_CHECK_VERSION
3614  * pre-processor macro
3615  *
3616  * Return value: %TRUE if the version of the Clutter library is
3617  *   greater than (@major, @minor, @micro), and %FALSE otherwise
3618  *
3619  * Since: 1.2
3620  */
3621 gboolean
3622 clutter_check_version (guint major,
3623                        guint minor,
3624                        guint micro)
3625 {
3626   return (clutter_major_version > major ||
3627           (clutter_major_version == major &&
3628            clutter_minor_version > minor) ||
3629           (clutter_major_version == major &&
3630            clutter_minor_version == minor &&
3631            clutter_micro_version >= micro));
3632 }
3633
3634 /**
3635  * clutter_get_default_text_direction:
3636  *
3637  * Retrieves the default direction for the text. The text direction is
3638  * determined by the locale and/or by the <varname>CLUTTER_TEXT_DIRECTION</varname>
3639  * environment variable.
3640  *
3641  * The default text direction can be overridden on a per-actor basis by using
3642  * clutter_actor_set_text_direction().
3643  *
3644  * Return value: the default text direction
3645  *
3646  * Since: 1.2
3647  */
3648 ClutterTextDirection
3649 clutter_get_default_text_direction (void)
3650 {
3651   return clutter_text_direction;
3652 }
3653
3654 /*< private >
3655  * clutter_clear_events_queue:
3656  *
3657  * Clears the events queue stored in the main context.
3658  */
3659 void
3660 _clutter_clear_events_queue (void)
3661 {
3662   ClutterMainContext *context = _clutter_context_get_default ();
3663
3664   if (context->events_queue != NULL)
3665     {
3666       g_queue_foreach (context->events_queue,
3667                        (GFunc) clutter_event_free,
3668                        NULL);
3669       g_queue_free (context->events_queue);
3670       context->events_queue = NULL;
3671     }
3672 }
3673
3674 guint32
3675 _clutter_context_acquire_id (gpointer key)
3676 {
3677   ClutterMainContext *context = _clutter_context_get_default ();
3678
3679   return _clutter_id_pool_add (context->id_pool, key);
3680 }
3681
3682 void
3683 _clutter_context_release_id (guint32 id_)
3684 {
3685   ClutterMainContext *context = _clutter_context_get_default ();
3686
3687   _clutter_id_pool_remove (context->id_pool, id_);
3688 }
3689
3690 void
3691 _clutter_clear_events_queue_for_stage (ClutterStage *stage)
3692 {
3693   ClutterMainContext *context = _clutter_context_get_default ();
3694   GList *l, *next;
3695
3696   if (context->events_queue == NULL)
3697     return;
3698
3699   /* Remove any pending events for this stage from the event queue */
3700   for (l = context->events_queue->head; l; l = next)
3701     {
3702       ClutterEvent *event = l->data;
3703
3704       next = l->next;
3705
3706       if (event->any.stage == stage)
3707         {
3708           g_queue_delete_link (context->events_queue, l);
3709           clutter_event_free (event);
3710         }
3711     }
3712 }
3713
3714 ClutterPickMode
3715 _clutter_context_get_pick_mode (void)
3716 {
3717   ClutterMainContext *context = _clutter_context_get_default ();
3718
3719   return context->pick_mode;
3720 }
3721
3722 void
3723 _clutter_context_push_shader_stack (ClutterActor *actor)
3724 {
3725   ClutterMainContext *context = _clutter_context_get_default ();
3726
3727   context->shaders = g_slist_prepend (context->shaders, actor);
3728 }
3729
3730 ClutterActor *
3731 _clutter_context_peek_shader_stack (void)
3732 {
3733   ClutterMainContext *context = _clutter_context_get_default ();
3734
3735   if (context->shaders != NULL)
3736     return context->shaders->data;
3737
3738   return NULL;
3739 }
3740
3741 ClutterActor *
3742 _clutter_context_pop_shader_stack (ClutterActor *actor)
3743 {
3744   ClutterMainContext *context = _clutter_context_get_default ();
3745
3746   context->shaders = g_slist_remove (context->shaders, actor);
3747
3748   return _clutter_context_peek_shader_stack ();
3749 }
3750
3751 gboolean
3752 _clutter_context_get_motion_events_enabled (void)
3753 {
3754   ClutterMainContext *context = _clutter_context_get_default ();
3755
3756   return context->motion_events_per_actor;
3757 }
3758
3759 /**
3760  * clutter_check_windowing_backend:
3761  * @backend_type: the name of the backend to check
3762  *
3763  * Checks the run-time name of the Clutter windowing system backend, using
3764  * the symbolic macros like %CLUTTER_WINDOWING_WIN32 or
3765  * %CLUTTER_WINDOWING_X11.
3766  *
3767  * This function should be used in conjuction with the compile-time macros
3768  * inside applications and libraries that are using the platform-specific
3769  * windowing system API, to ensure that they are running on the correct
3770  * windowing system; for instance:
3771  *
3772  * |[
3773  * &num;ifdef CLUTTER_WINDOWING_X11
3774  *   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
3775  *     {
3776  *       /&ast; it is safe to use the clutter_x11_* API &ast;/
3777  *     }
3778  *   else
3779  * &num;endif
3780  * &num;ifdef CLUTTER_WINDOWING_WIN32
3781  *   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32))
3782  *     {
3783  *       /&ast; it is safe to use the clutter_win32_* API &ast;/
3784  *     }
3785  *   else
3786  * &num;endif
3787  *     g_error ("Unknown Clutter backend.");
3788  * ]|
3789  *
3790  * Return value: %TRUE if the current Clutter windowing system backend is
3791  *   the one checked, and %FALSE otherwise
3792  *
3793  * Since: 1.10
3794  */
3795 gboolean
3796 clutter_check_windowing_backend (const char *backend_type)
3797 {
3798   ClutterMainContext *context = _clutter_context_get_default ();
3799
3800   g_return_val_if_fail (backend_type != NULL, FALSE);
3801
3802   backend_type = g_intern_string (backend_type);
3803
3804 #ifdef CLUTTER_WINDOWING_OSX
3805   if (backend_type == I_(CLUTTER_WINDOWING_OSX) &&
3806       CLUTTER_IS_BACKEND_OSX (context->backend))
3807     return TRUE;
3808   else
3809 #endif
3810 #ifdef CLUTTER_WINDOWING_WIN32
3811   if (backend_type == I_(CLUTTER_WINDOWING_WIN32) &&
3812       CLUTTER_IS_BACKEND_WIN32 (context->backend))
3813     return TRUE;
3814   else
3815 #endif
3816 #ifdef CLUTTER_WINDOWING_WAYLAND
3817   if (backend_type == I_(CLUTTER_WINDOWING_WAYLAND) &&
3818       CLUTTER_IS_BACKEND_WAYLAND (context->backend))
3819     return TRUE;
3820   else
3821 #endif
3822 #ifdef CLUTTER_WINDOWING_EGL
3823   if (backend_type == I_(CLUTTER_WINDOWING_EGL) &&
3824       CLUTTER_IS_BACKEND_EGL_NATIVE (context->backend))
3825     return TRUE;
3826   else
3827 #endif
3828 #ifdef CLUTTER_WINDOWING_GDK
3829   if (backend_type == I_(CLUTTER_WINDOWING_GDK) &&
3830       CLUTTER_IS_BACKEND_GDK (context->backend))
3831     return TRUE;
3832   else
3833 #endif
3834 #ifdef CLUTTER_WINDOWING_X11
3835   if (backend_type == I_(CLUTTER_WINDOWING_X11) &&
3836       CLUTTER_IS_BACKEND_X11 (context->backend))
3837     return TRUE;
3838   else
3839 #endif
3840   return FALSE;
3841 }
3842
3843 gboolean
3844 _clutter_get_sync_to_vblank (void)
3845 {
3846   return clutter_sync_to_vblank;
3847 }
3848
3849 void
3850 _clutter_debug_messagev (const char *format,
3851                          va_list     var_args)
3852 {
3853   gchar *stamp, *fmt;
3854
3855   stamp = g_strdup_printf ("[%16" G_GINT64_FORMAT "]",
3856                            g_get_monotonic_time ());
3857   fmt = g_strconcat (stamp, ":", format, NULL);
3858   g_free (stamp);
3859
3860   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, var_args);
3861
3862 #ifdef CLUTTER_ENABLE_PROFILE
3863   if (_clutter_uprof_context != NULL)
3864     uprof_context_vtrace_message (_clutter_uprof_context, format, var_args);
3865 #endif
3866
3867   g_free (fmt);
3868 }
3869
3870 void
3871 _clutter_debug_message (const char *format, ...)
3872 {
3873   va_list args;
3874
3875   va_start (args, format);
3876   _clutter_debug_messagev (format, args);
3877   va_end (args);
3878 }
3879
3880 gboolean
3881 _clutter_diagnostic_enabled (void)
3882 {
3883   static const char *clutter_enable_diagnostic = NULL;
3884
3885   if (G_UNLIKELY (clutter_enable_diagnostic == NULL))
3886     {
3887       clutter_enable_diagnostic = g_getenv ("CLUTTER_ENABLE_DIAGNOSTIC");
3888
3889       if (clutter_enable_diagnostic == NULL)
3890         clutter_enable_diagnostic = "0";
3891     }
3892
3893   return *clutter_enable_diagnostic != '0';
3894 }
3895
3896 void
3897 _clutter_diagnostic_message (const char *format, ...)
3898 {
3899   va_list args;
3900   char *fmt;
3901
3902   fmt = g_strconcat ("[DIAGNOSTIC]: ", format, NULL);
3903
3904   va_start (args, format);
3905   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args);
3906   va_end (args);
3907
3908   g_free (fmt);
3909 }