cleanup specfile for packaging
[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="../../../../tests/interactive/test-thread.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       case CLUTTER_TOUCH_CANCEL:
2618         break;
2619
2620       case CLUTTER_STAGE_STATE:
2621         /* fullscreen / focus - forward to stage */
2622         event->any.source = stage;
2623         clutter_stage_event (CLUTTER_STAGE (stage), event);
2624         break;
2625
2626       case CLUTTER_CLIENT_MESSAGE:
2627         break;
2628
2629       case CLUTTER_EVENT_LAST:
2630         break;
2631     }
2632 }
2633
2634 /*
2635  * _clutter_process_event
2636  * @event: a #ClutterEvent.
2637  *
2638  * Does the actual work of processing an event that was queued earlier
2639  * out of clutter_do_event().
2640  */
2641 void
2642 _clutter_process_event (ClutterEvent *event)
2643 {
2644   ClutterMainContext *context;
2645   ClutterActor *stage;
2646
2647   context = _clutter_context_get_default ();
2648
2649   stage = CLUTTER_ACTOR (event->any.stage);
2650   if (stage == NULL)
2651     return;
2652
2653   CLUTTER_NOTE (EVENT, "Event received");
2654
2655   context->last_event_time = clutter_event_get_time (event);
2656
2657   context->current_event = event;
2658   _clutter_process_event_details (stage, context, event);
2659   context->current_event = NULL;
2660 }
2661
2662 /**
2663  * clutter_get_actor_by_gid:
2664  * @id_: a #ClutterActor unique id.
2665  *
2666  * Retrieves the #ClutterActor with @id_.
2667  *
2668  * Return value: (transfer none): the actor with the passed id or %NULL.
2669  *   The returned actor does not have its reference count increased.
2670  *
2671  * Since: 0.6
2672  *
2673  * Deprecated: 1.8: The id is not used any longer.
2674  */
2675 ClutterActor *
2676 clutter_get_actor_by_gid (guint32 id_)
2677 {
2678   return _clutter_get_actor_by_id (NULL, id_);
2679 }
2680
2681 void
2682 clutter_base_init (void)
2683 {
2684   static gboolean initialised = FALSE;
2685
2686   if (!initialised)
2687     {
2688       initialised = TRUE;
2689
2690       bindtextdomain (GETTEXT_PACKAGE, CLUTTER_LOCALEDIR);
2691       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2692
2693       /* initialise GLib type system */
2694       g_type_init ();
2695
2696       /* initialise the Big Clutter Lockâ„¢ if necessary */
2697       clutter_threads_init_default ();
2698     }
2699 }
2700
2701 /**
2702  * clutter_get_default_frame_rate:
2703  *
2704  * Retrieves the default frame rate. See clutter_set_default_frame_rate().
2705  *
2706  * Return value: the default frame rate
2707  *
2708  * Since: 0.6
2709  */
2710 guint
2711 clutter_get_default_frame_rate (void)
2712 {
2713   ClutterMainContext *context;
2714
2715   context = _clutter_context_get_default ();
2716
2717   return context->frame_rate;
2718 }
2719
2720 /**
2721  * clutter_set_default_frame_rate:
2722  * @frames_per_sec: the new default frame rate
2723  *
2724  * Sets the default frame rate. This frame rate will be used to limit
2725  * the number of frames drawn if Clutter is not able to synchronize
2726  * with the vertical refresh rate of the display. When synchronization
2727  * is possible, this value is ignored.
2728  *
2729  * Since: 0.6
2730  *
2731  * Deprecated: 1.10: This function does not do anything any more.
2732  */
2733 void
2734 clutter_set_default_frame_rate (guint frames_per_sec)
2735 {
2736 }
2737
2738 static void
2739 on_grab_actor_destroy (ClutterActor       *actor,
2740                        ClutterInputDevice *device)
2741 {
2742   if (device == NULL)
2743     {
2744       ClutterMainContext *context = _clutter_context_get_default ();
2745
2746       if (context->pointer_grab_actor == actor)
2747         clutter_ungrab_pointer ();
2748
2749       if (context->keyboard_grab_actor == actor)
2750         clutter_ungrab_keyboard ();
2751
2752       return;
2753     }
2754
2755   switch (device->device_type)
2756     {
2757     case CLUTTER_POINTER_DEVICE:
2758       device->pointer_grab_actor = NULL;
2759       break;
2760
2761     case CLUTTER_KEYBOARD_DEVICE:
2762       device->keyboard_grab_actor = NULL;
2763       break;
2764
2765     default:
2766       g_assert_not_reached ();
2767     }
2768 }
2769
2770 /**
2771  * clutter_grab_pointer:
2772  * @actor: a #ClutterActor
2773  *
2774  * Grabs pointer events, after the grab is done all pointer related events
2775  * (press, motion, release, enter, leave and scroll) are delivered to this
2776  * actor directly without passing through both capture and bubble phases of
2777  * the event delivery chain. The source set in the event will be the actor
2778  * that would have received the event if the pointer grab was not in effect.
2779  *
2780  * <note><para>Grabs completely override the entire event delivery chain
2781  * done by Clutter. Pointer grabs should only be used as a last resource;
2782  * using the #ClutterActor::captured-event signal should always be the
2783  * preferred way to intercept event delivery to reactive actors.</para></note>
2784  *
2785  * This function should rarely be used.
2786  *
2787  * If a grab is required, you are strongly encouraged to use a specific
2788  * input device by calling clutter_input_device_grab().
2789  *
2790  * Since: 0.6
2791  */
2792 void
2793 clutter_grab_pointer (ClutterActor *actor)
2794 {
2795   ClutterMainContext *context;
2796
2797   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2798
2799   context = _clutter_context_get_default ();
2800
2801   if (context->pointer_grab_actor == actor)
2802     return;
2803
2804   if (context->pointer_grab_actor != NULL)
2805     {
2806       g_signal_handlers_disconnect_by_func (context->pointer_grab_actor,
2807                                             G_CALLBACK (on_grab_actor_destroy),
2808                                             NULL);
2809       context->pointer_grab_actor = NULL;
2810     }
2811
2812   if (actor != NULL)
2813     {
2814       context->pointer_grab_actor = actor;
2815
2816       g_signal_connect (context->pointer_grab_actor, "destroy",
2817                         G_CALLBACK (on_grab_actor_destroy),
2818                         NULL);
2819     }
2820 }
2821
2822 /**
2823  * clutter_input_device_grab:
2824  * @device: a #ClutterInputDevice
2825  * @actor: a #ClutterActor
2826  *
2827  * Acquires a grab on @actor for the given @device.
2828  *
2829  * Any event coming from @device will be delivered to @actor, bypassing
2830  * the usual event delivery mechanism, until the grab is released by
2831  * calling clutter_input_device_ungrab().
2832  *
2833  * The grab is client-side: even if the windowing system used by the Clutter
2834  * backend has the concept of "device grabs", Clutter will not use them.
2835  *
2836  * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE and
2837  * %CLUTTER_KEYBOARD_DEVICE can hold a grab.
2838  *
2839  * Since: 1.10
2840  */
2841 void
2842 clutter_input_device_grab (ClutterInputDevice *device,
2843                            ClutterActor       *actor)
2844 {
2845   ClutterActor **grab_actor;
2846
2847   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2848   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
2849
2850   switch (device->device_type)
2851     {
2852     case CLUTTER_POINTER_DEVICE:
2853       grab_actor = &(device->pointer_grab_actor);
2854       break;
2855
2856     case CLUTTER_KEYBOARD_DEVICE:
2857       grab_actor = &(device->keyboard_grab_actor);
2858       break;
2859
2860     default:
2861       g_critical ("Only pointer and keyboard devices can grab an actor");
2862       return;
2863     }
2864
2865   if (*grab_actor != NULL)
2866     {
2867       g_signal_handlers_disconnect_by_func (*grab_actor,
2868                                             G_CALLBACK (on_grab_actor_destroy),
2869                                             device);
2870     }
2871
2872   *grab_actor = actor;
2873
2874   g_signal_connect (*grab_actor,
2875                     "destroy",
2876                     G_CALLBACK (on_grab_actor_destroy),
2877                     device);
2878 }
2879
2880 /**
2881  * clutter_input_device_ungrab:
2882  * @device: a #ClutterInputDevice
2883  *
2884  * Releases the grab on the @device, if one is in place.
2885  *
2886  * Since: 1.10
2887  */
2888 void
2889 clutter_input_device_ungrab (ClutterInputDevice *device)
2890 {
2891   ClutterActor **grab_actor;
2892
2893   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
2894
2895   switch (device->device_type)
2896     {
2897     case CLUTTER_POINTER_DEVICE:
2898       grab_actor = &(device->pointer_grab_actor);
2899       break;
2900
2901     case CLUTTER_KEYBOARD_DEVICE:
2902       grab_actor = &(device->keyboard_grab_actor);
2903       break;
2904
2905     default:
2906       return;
2907     }
2908
2909   if (*grab_actor == NULL)
2910     return;
2911
2912   g_signal_handlers_disconnect_by_func (*grab_actor,
2913                                         G_CALLBACK (on_grab_actor_destroy),
2914                                         device);
2915
2916   *grab_actor = NULL;
2917 }
2918
2919 /**
2920  * clutter_input_device_get_grabbed_actor:
2921  * @device: a #ClutterInputDevice
2922  *
2923  * Retrieves a pointer to the #ClutterActor currently grabbing all
2924  * the events coming from @device.
2925  *
2926  * Return value: (transfer none): a #ClutterActor, or %NULL
2927  *
2928  * Since: 1.10
2929  */
2930 ClutterActor *
2931 clutter_input_device_get_grabbed_actor (ClutterInputDevice *device)
2932 {
2933   g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
2934
2935   switch (device->device_type)
2936     {
2937     case CLUTTER_POINTER_DEVICE:
2938       return device->pointer_grab_actor;
2939
2940     case CLUTTER_KEYBOARD_DEVICE:
2941       return device->keyboard_grab_actor;
2942
2943     default:
2944       g_critical ("Only pointer and keyboard devices can grab an actor");
2945     }
2946
2947   return NULL;
2948 }
2949
2950 /**
2951  * clutter_grab_pointer_for_device:
2952  * @actor: a #ClutterActor
2953  * @id_: a device id, or -1
2954  *
2955  * Grabs all the pointer events coming from the device @id for @actor.
2956  *
2957  * If @id is -1 then this function is equivalent to clutter_grab_pointer().
2958  *
2959  * Since: 0.8
2960  *
2961  * Deprecated: 1.10: Use clutter_input_device_grab() instead.
2962  */
2963 void
2964 clutter_grab_pointer_for_device (ClutterActor *actor,
2965                                  gint          id_)
2966 {
2967   ClutterDeviceManager *manager;
2968   ClutterInputDevice *dev;
2969
2970   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
2971
2972   /* essentially a global grab */
2973   if (id_ == -1)
2974     {
2975       if (actor == NULL)
2976         clutter_ungrab_pointer ();
2977       else
2978         clutter_grab_pointer (actor);
2979
2980       return;
2981     }
2982
2983   manager = clutter_device_manager_get_default ();
2984   dev = clutter_device_manager_get_device (manager, id_);
2985   if (dev == NULL)
2986     return;
2987
2988   if (dev->device_type != CLUTTER_POINTER_DEVICE)
2989     return;
2990
2991   if (actor == NULL)
2992     clutter_input_device_ungrab (dev);
2993   else
2994     clutter_input_device_grab (dev, actor);
2995 }
2996
2997
2998 /**
2999  * clutter_ungrab_pointer:
3000  *
3001  * Removes an existing grab of the pointer.
3002  *
3003  * Since: 0.6
3004  */
3005 void
3006 clutter_ungrab_pointer (void)
3007 {
3008   clutter_grab_pointer (NULL);
3009 }
3010
3011 /**
3012  * clutter_ungrab_pointer_for_device:
3013  * @id_: a device id
3014  *
3015  * Removes an existing grab of the pointer events for device @id_.
3016  *
3017  * Since: 0.8
3018  *
3019  * Deprecated: 1.10: Use clutter_input_device_ungrab() instead.
3020  */
3021 void
3022 clutter_ungrab_pointer_for_device (gint id_)
3023 {
3024   ClutterDeviceManager *manager;
3025   ClutterInputDevice *device;
3026
3027   manager = clutter_device_manager_get_default ();
3028   device = clutter_device_manager_get_device (manager, id_);
3029   if (device != NULL)
3030     clutter_input_device_ungrab (device);
3031 }
3032
3033
3034 /**
3035  * clutter_get_pointer_grab:
3036  *
3037  * Queries the current pointer grab of clutter.
3038  *
3039  * Return value: (transfer none): the actor currently holding the pointer grab, or NULL if there is no grab.
3040  *
3041  * Since: 0.6
3042  */
3043 ClutterActor *
3044 clutter_get_pointer_grab (void)
3045 {
3046   ClutterMainContext *context;
3047   context = _clutter_context_get_default ();
3048
3049   return context->pointer_grab_actor;
3050 }
3051
3052
3053 /**
3054  * clutter_grab_keyboard:
3055  * @actor: a #ClutterActor
3056  *
3057  * Grabs keyboard events, after the grab is done keyboard
3058  * events (#ClutterActor::key-press-event and #ClutterActor::key-release-event)
3059  * are delivered to this actor directly. The source set in the event will be
3060  * the actor that would have received the event if the keyboard grab was not
3061  * in effect.
3062  *
3063  * Like pointer grabs, keyboard grabs should only be used as a last
3064  * resource.
3065  *
3066  * See also clutter_stage_set_key_focus() and clutter_actor_grab_key_focus()
3067  * to perform a "soft" key grab and assign key focus to a specific actor.
3068  *
3069  * Since: 0.6
3070  */
3071 void
3072 clutter_grab_keyboard (ClutterActor *actor)
3073 {
3074   ClutterMainContext *context;
3075
3076   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
3077
3078   context = _clutter_context_get_default ();
3079
3080   if (context->keyboard_grab_actor == actor)
3081     return;
3082
3083   if (context->keyboard_grab_actor != NULL)
3084     {
3085       g_signal_handlers_disconnect_by_func (context->keyboard_grab_actor,
3086                                             G_CALLBACK (on_grab_actor_destroy),
3087                                             NULL);
3088       context->keyboard_grab_actor = NULL;
3089     }
3090
3091   if (actor != NULL)
3092     {
3093       context->keyboard_grab_actor = actor;
3094
3095       g_signal_connect (context->keyboard_grab_actor, "destroy",
3096                         G_CALLBACK (on_grab_actor_destroy),
3097                         NULL);
3098     }
3099 }
3100
3101 /**
3102  * clutter_ungrab_keyboard:
3103  *
3104  * Removes an existing grab of the keyboard.
3105  *
3106  * Since: 0.6
3107  */
3108 void
3109 clutter_ungrab_keyboard (void)
3110 {
3111   clutter_grab_keyboard (NULL);
3112 }
3113
3114 /**
3115  * clutter_get_keyboard_grab:
3116  *
3117  * Queries the current keyboard grab of clutter.
3118  *
3119  * Return value: (transfer none): the actor currently holding the keyboard grab, or NULL if there is no grab.
3120  *
3121  * Since: 0.6
3122  */
3123 ClutterActor *
3124 clutter_get_keyboard_grab (void)
3125 {
3126   ClutterMainContext *context;
3127
3128   context = _clutter_context_get_default ();
3129
3130   return context->keyboard_grab_actor;
3131 }
3132
3133 /**
3134  * clutter_clear_glyph_cache:
3135  *
3136  * Clears the internal cache of glyphs used by the Pango
3137  * renderer. This will free up some memory and GL texture
3138  * resources. The cache will be automatically refilled as more text is
3139  * drawn.
3140  *
3141  * Since: 0.8
3142  *
3143  * Deprecated: 1.10: Use clutter_get_font_map() and
3144  *   cogl_pango_font_map_clear_glyph_cache() instead.
3145  */
3146 void
3147 clutter_clear_glyph_cache (void)
3148 {
3149   CoglPangoFontMap *font_map;
3150
3151   font_map = clutter_context_get_pango_fontmap ();
3152   cogl_pango_font_map_clear_glyph_cache (font_map);
3153 }
3154
3155 /**
3156  * clutter_set_font_flags:
3157  * @flags: The new flags
3158  *
3159  * Sets the font quality options for subsequent text rendering
3160  * operations.
3161  *
3162  * Using mipmapped textures will improve the quality for scaled down
3163  * text but will use more texture memory.
3164  *
3165  * Enabling hinting improves text quality for static text but may
3166  * introduce some artifacts if the text is animated.
3167  *
3168  * Since: 1.0
3169  *
3170  * Deprecated: 1.10: Use clutter_backend_set_font_options() and the
3171  *   #cairo_font_option_t API.
3172  */
3173 void
3174 clutter_set_font_flags (ClutterFontFlags flags)
3175 {
3176   ClutterMainContext *context = _clutter_context_get_default ();
3177   CoglPangoFontMap *font_map;
3178   ClutterFontFlags old_flags, changed_flags;
3179   const cairo_font_options_t *font_options;
3180   cairo_font_options_t *new_font_options;
3181   cairo_hint_style_t hint_style;
3182   gboolean use_mipmapping;
3183   ClutterBackend *backend;
3184
3185   backend = clutter_get_default_backend ();
3186   font_map = clutter_context_get_pango_fontmap ();
3187   font_options = clutter_backend_get_font_options (backend);
3188   old_flags = 0;
3189
3190   if (cogl_pango_font_map_get_use_mipmapping (font_map))
3191     old_flags |= CLUTTER_FONT_MIPMAPPING;
3192
3193   hint_style = cairo_font_options_get_hint_style (font_options);
3194   if (hint_style != CAIRO_HINT_STYLE_DEFAULT &&
3195       hint_style != CAIRO_HINT_STYLE_NONE)
3196     old_flags |= CLUTTER_FONT_HINTING;
3197
3198   if (old_flags == flags)
3199     return;
3200
3201   new_font_options = cairo_font_options_copy (font_options);
3202
3203   /* Only set the font options that have actually changed so we don't
3204      override a detailed setting from the backend */
3205   changed_flags = old_flags ^ flags;
3206
3207   if ((changed_flags & CLUTTER_FONT_MIPMAPPING))
3208     {
3209       use_mipmapping = (changed_flags & CLUTTER_FONT_MIPMAPPING) != 0;
3210
3211       cogl_pango_font_map_set_use_mipmapping (font_map, use_mipmapping);
3212     }
3213
3214   if ((changed_flags & CLUTTER_FONT_HINTING))
3215     {
3216       hint_style = (flags & CLUTTER_FONT_HINTING)
3217                  ? CAIRO_HINT_STYLE_FULL
3218                  : CAIRO_HINT_STYLE_NONE;
3219
3220       cairo_font_options_set_hint_style (new_font_options, hint_style);
3221     }
3222
3223   clutter_backend_set_font_options (backend, new_font_options);
3224
3225   cairo_font_options_destroy (new_font_options);
3226
3227   /* update the default pango context, if any */
3228   if (context->pango_context != NULL)
3229     update_pango_context (backend, context->pango_context);
3230 }
3231
3232 /**
3233  * clutter_get_font_flags:
3234  *
3235  * Gets the current font flags for rendering text. See
3236  * clutter_set_font_flags().
3237  *
3238  * Return value: The font flags
3239  *
3240  * Since: 1.0
3241  *
3242  * Deprecated: 1.10: Use clutter_backend_get_font_options() and the
3243  *   #cairo_font_options_t API.
3244  */
3245 ClutterFontFlags
3246 clutter_get_font_flags (void)
3247 {
3248   CoglPangoFontMap *font_map = NULL;
3249   const cairo_font_options_t *font_options;
3250   ClutterFontFlags flags = 0;
3251   cairo_hint_style_t hint_style;
3252
3253   font_map = clutter_context_get_pango_fontmap ();
3254   if (cogl_pango_font_map_get_use_mipmapping (font_map))
3255     flags |= CLUTTER_FONT_MIPMAPPING;
3256
3257   font_options =
3258     clutter_backend_get_font_options (clutter_get_default_backend ());
3259
3260   hint_style = cairo_font_options_get_hint_style (font_options);
3261   if (hint_style != CAIRO_HINT_STYLE_DEFAULT &&
3262       hint_style != CAIRO_HINT_STYLE_NONE)
3263     flags |= CLUTTER_FONT_HINTING;
3264
3265   return flags;
3266 }
3267
3268 /**
3269  * clutter_get_input_device_for_id:
3270  * @id_: the unique id for a device
3271  *
3272  * Retrieves the #ClutterInputDevice from its @id_. This is a convenience
3273  * wrapper for clutter_device_manager_get_device() and it is functionally
3274  * equivalent to:
3275  *
3276  * |[
3277  *   ClutterDeviceManager *manager;
3278  *   ClutterInputDevice *device;
3279  *
3280  *   manager = clutter_device_manager_get_default ();
3281  *   device = clutter_device_manager_get_device (manager, id);
3282  * ]|
3283  *
3284  * Return value: (transfer none): a #ClutterInputDevice, or %NULL
3285  *
3286  * Since: 0.8
3287  *
3288  * Deprecated: 1.10: Use clutter_device_manager_get_device() instead.
3289  */
3290 ClutterInputDevice *
3291 clutter_get_input_device_for_id (gint id_)
3292 {
3293   ClutterDeviceManager *manager;
3294
3295   manager = clutter_device_manager_get_default ();
3296
3297   return clutter_device_manager_get_device (manager, id_);
3298 }
3299
3300 /**
3301  * clutter_get_font_map:
3302  *
3303  * Retrieves the #PangoFontMap instance used by Clutter.
3304  * You can use the global font map object with the COGL
3305  * Pango API.
3306  *
3307  * Return value: (transfer none): the #PangoFontMap instance. The returned
3308  *   value is owned by Clutter and it should never be unreferenced.
3309  *
3310  * Since: 1.0
3311  */
3312 PangoFontMap *
3313 clutter_get_font_map (void)
3314 {
3315   return PANGO_FONT_MAP (clutter_context_get_pango_fontmap ());
3316 }
3317
3318 typedef struct _ClutterRepaintFunction
3319 {
3320   guint id;
3321   ClutterRepaintFlags flags;
3322   GSourceFunc func;
3323   gpointer data;
3324   GDestroyNotify notify;
3325 } ClutterRepaintFunction;
3326
3327 /**
3328  * clutter_threads_remove_repaint_func:
3329  * @handle_id: an unsigned integer greater than zero
3330  *
3331  * Removes the repaint function with @handle_id as its id
3332  *
3333  * Since: 1.0
3334  */
3335 void
3336 clutter_threads_remove_repaint_func (guint handle_id)
3337 {
3338   ClutterRepaintFunction *repaint_func;
3339   ClutterMainContext *context;
3340   GList *l;
3341
3342   g_return_if_fail (handle_id > 0);
3343
3344   _clutter_context_lock ();
3345
3346   context = clutter_context_get_default_unlocked ();
3347   l = context->repaint_funcs;
3348   while (l != NULL)
3349     {
3350       repaint_func = l->data;
3351
3352       if (repaint_func->id == handle_id)
3353         {
3354           context->repaint_funcs =
3355             g_list_remove_link (context->repaint_funcs, l);
3356
3357           g_list_free (l);
3358
3359           if (repaint_func->notify)
3360             repaint_func->notify (repaint_func->data);
3361
3362           g_slice_free (ClutterRepaintFunction, repaint_func);
3363
3364           break;
3365         }
3366
3367       l = l->next;
3368     }
3369
3370   _clutter_context_unlock ();
3371 }
3372
3373 /**
3374  * clutter_threads_add_repaint_func:
3375  * @func: the function to be called within the paint cycle
3376  * @data: data to be passed to the function, or %NULL
3377  * @notify: function to be called when removing the repaint
3378  *    function, or %NULL
3379  *
3380  * Adds a function to be called whenever Clutter is processing a new
3381  * frame.
3382  *
3383  * If the function returns %FALSE it is automatically removed from the
3384  * list of repaint functions and will not be called again.
3385  *
3386  * This function is guaranteed to be called from within the same thread
3387  * that called clutter_main(), and while the Clutter lock is being held;
3388  * the function will be called within the main loop, so it is imperative
3389  * that it does not block, otherwise the frame time budget may be lost.
3390  *
3391  * A repaint function is useful to ensure that an update of the scenegraph
3392  * is performed before the scenegraph is repainted; for instance, uploading
3393  * a frame from a video into a #ClutterTexture. By default, a repaint
3394  * function added using this function will be invoked prior to the frame
3395  * being processed.
3396  *
3397  * Adding a repaint function does not automatically ensure that a new
3398  * frame will be queued.
3399  *
3400  * When the repaint function is removed (either because it returned %FALSE
3401  * or because clutter_threads_remove_repaint_func() has been called) the
3402  * @notify function will be called, if any is set.
3403  *
3404  * See also: clutter_threads_add_repaint_func_full()
3405  *
3406  * Return value: the ID (greater than 0) of the repaint function. You
3407  *   can use the returned integer to remove the repaint function by
3408  *   calling clutter_threads_remove_repaint_func().
3409  *
3410  * Since: 1.0
3411  */
3412 guint
3413 clutter_threads_add_repaint_func (GSourceFunc    func,
3414                                   gpointer       data,
3415                                   GDestroyNotify notify)
3416 {
3417   return clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
3418                                                 func,
3419                                                 data, notify);
3420 }
3421
3422 /**
3423  * clutter_threads_add_repaint_func_full:
3424  * @flags: flags for the repaint function
3425  * @func: the function to be called within the paint cycle
3426  * @data: data to be passed to the function, or %NULL
3427  * @notify: function to be called when removing the repaint
3428  *    function, or %NULL
3429  *
3430  * Adds a function to be called whenever Clutter is processing a new
3431  * frame.
3432  *
3433  * If the function returns %FALSE it is automatically removed from the
3434  * list of repaint functions and will not be called again.
3435  *
3436  * This function is guaranteed to be called from within the same thread
3437  * that called clutter_main(), and while the Clutter lock is being held;
3438  * the function will be called within the main loop, so it is imperative
3439  * that it does not block, otherwise the frame time budget may be lost.
3440  *
3441  * A repaint function is useful to ensure that an update of the scenegraph
3442  * is performed before the scenegraph is repainted; for instance, uploading
3443  * a frame from a video into a #ClutterTexture. The @flags passed to this
3444  * function will determine the section of the frame processing that will
3445  * result in @func being called.
3446  *
3447  * Adding a repaint function does not automatically ensure that a new
3448  * frame will be queued.
3449  *
3450  * When the repaint function is removed (either because it returned %FALSE
3451  * or because clutter_threads_remove_repaint_func() has been called) the
3452  * @notify function will be called, if any is set.
3453  *
3454  * Return value: the ID (greater than 0) of the repaint function. You
3455  *   can use the returned integer to remove the repaint function by
3456  *   calling clutter_threads_remove_repaint_func().
3457  *
3458  * Since: 1.10
3459  */
3460 guint
3461 clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
3462                                        GSourceFunc         func,
3463                                        gpointer            data,
3464                                        GDestroyNotify      notify)
3465 {
3466   ClutterMainContext *context;
3467   ClutterRepaintFunction *repaint_func;
3468
3469   g_return_val_if_fail (func != NULL, 0);
3470
3471   _clutter_context_lock ();
3472
3473   context = clutter_context_get_default_unlocked ();
3474
3475   repaint_func = g_slice_new (ClutterRepaintFunction);
3476
3477   repaint_func->id = context->last_repaint_id++;
3478
3479   /* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */
3480   repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD;
3481   repaint_func->func = func;
3482   repaint_func->data = data;
3483   repaint_func->notify = notify;
3484
3485   context->repaint_funcs = g_list_prepend (context->repaint_funcs,
3486                                            repaint_func);
3487
3488   _clutter_context_unlock ();
3489
3490   if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0)
3491     {
3492       ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
3493
3494       _clutter_master_clock_ensure_next_iteration (master_clock);
3495     }
3496
3497   return repaint_func->id;
3498 }
3499
3500 /*
3501  * _clutter_run_repaint_functions:
3502  * @flags: only run the repaint functions matching the passed flags
3503  *
3504  * Executes the repaint functions added using the
3505  * clutter_threads_add_repaint_func() function.
3506  *
3507  * Must be called with the Clutter thread lock held.
3508  */
3509 void
3510 _clutter_run_repaint_functions (ClutterRepaintFlags flags)
3511 {
3512   ClutterMainContext *context = _clutter_context_get_default ();
3513   ClutterRepaintFunction *repaint_func;
3514   GList *invoke_list, *reinvoke_list, *l;
3515
3516   if (context->repaint_funcs == NULL)
3517     return;
3518
3519   /* steal the list */
3520   invoke_list = context->repaint_funcs;
3521   context->repaint_funcs = NULL;
3522
3523   reinvoke_list = NULL;
3524
3525   /* consume the whole list while we execute the functions */
3526   while (invoke_list != NULL)
3527     {
3528       gboolean res = FALSE;
3529
3530       repaint_func = invoke_list->data;
3531
3532       l = invoke_list;
3533       invoke_list = g_list_remove_link (invoke_list, invoke_list);
3534
3535       g_list_free (l);
3536
3537       if ((repaint_func->flags & flags) != 0)
3538         res = repaint_func->func (repaint_func->data);
3539       else
3540         res = TRUE;
3541
3542       if (res)
3543         reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
3544       else
3545         {
3546           if (repaint_func->notify != NULL)
3547             repaint_func->notify (repaint_func->data);
3548
3549           g_slice_free (ClutterRepaintFunction, repaint_func);
3550         }
3551     }
3552
3553   if (context->repaint_funcs != NULL)
3554     {
3555       context->repaint_funcs = g_list_concat (context->repaint_funcs,
3556                                               g_list_reverse (reinvoke_list));
3557     }
3558   else
3559     context->repaint_funcs = g_list_reverse (reinvoke_list);
3560 }
3561
3562 /**
3563  * clutter_check_version:
3564  * @major: major version, like 1 in 1.2.3
3565  * @minor: minor version, like 2 in 1.2.3
3566  * @micro: micro version, like 3 in 1.2.3
3567  *
3568  * Run-time version check, to check the version the Clutter library
3569  * that an application is currently linked against
3570  *
3571  * This is the run-time equivalent of the compile-time %CLUTTER_CHECK_VERSION
3572  * pre-processor macro
3573  *
3574  * Return value: %TRUE if the version of the Clutter library is
3575  *   greater than (@major, @minor, @micro), and %FALSE otherwise
3576  *
3577  * Since: 1.2
3578  */
3579 gboolean
3580 clutter_check_version (guint major,
3581                        guint minor,
3582                        guint micro)
3583 {
3584   return (clutter_major_version > major ||
3585           (clutter_major_version == major &&
3586            clutter_minor_version > minor) ||
3587           (clutter_major_version == major &&
3588            clutter_minor_version == minor &&
3589            clutter_micro_version >= micro));
3590 }
3591
3592 /**
3593  * clutter_get_default_text_direction:
3594  *
3595  * Retrieves the default direction for the text. The text direction is
3596  * determined by the locale and/or by the <varname>CLUTTER_TEXT_DIRECTION</varname>
3597  * environment variable.
3598  *
3599  * The default text direction can be overridden on a per-actor basis by using
3600  * clutter_actor_set_text_direction().
3601  *
3602  * Return value: the default text direction
3603  *
3604  * Since: 1.2
3605  */
3606 ClutterTextDirection
3607 clutter_get_default_text_direction (void)
3608 {
3609   return clutter_text_direction;
3610 }
3611
3612 /*< private >
3613  * clutter_clear_events_queue:
3614  *
3615  * Clears the events queue stored in the main context.
3616  */
3617 void
3618 _clutter_clear_events_queue (void)
3619 {
3620   ClutterMainContext *context = _clutter_context_get_default ();
3621
3622   if (context->events_queue != NULL)
3623     {
3624       g_queue_foreach (context->events_queue,
3625                        (GFunc) clutter_event_free,
3626                        NULL);
3627       g_queue_free (context->events_queue);
3628       context->events_queue = NULL;
3629     }
3630 }
3631
3632 guint32
3633 _clutter_context_acquire_id (gpointer key)
3634 {
3635   ClutterMainContext *context = _clutter_context_get_default ();
3636
3637   return _clutter_id_pool_add (context->id_pool, key);
3638 }
3639
3640 void
3641 _clutter_context_release_id (guint32 id_)
3642 {
3643   ClutterMainContext *context = _clutter_context_get_default ();
3644
3645   _clutter_id_pool_remove (context->id_pool, id_);
3646 }
3647
3648 void
3649 _clutter_clear_events_queue_for_stage (ClutterStage *stage)
3650 {
3651   ClutterMainContext *context = _clutter_context_get_default ();
3652   GList *l, *next;
3653
3654   if (context->events_queue == NULL)
3655     return;
3656
3657   /* Remove any pending events for this stage from the event queue */
3658   for (l = context->events_queue->head; l; l = next)
3659     {
3660       ClutterEvent *event = l->data;
3661
3662       next = l->next;
3663
3664       if (event->any.stage == stage)
3665         {
3666           g_queue_delete_link (context->events_queue, l);
3667           clutter_event_free (event);
3668         }
3669     }
3670 }
3671
3672 ClutterPickMode
3673 _clutter_context_get_pick_mode (void)
3674 {
3675   ClutterMainContext *context = _clutter_context_get_default ();
3676
3677   return context->pick_mode;
3678 }
3679
3680 void
3681 _clutter_context_push_shader_stack (ClutterActor *actor)
3682 {
3683   ClutterMainContext *context = _clutter_context_get_default ();
3684
3685   context->shaders = g_slist_prepend (context->shaders, actor);
3686 }
3687
3688 ClutterActor *
3689 _clutter_context_peek_shader_stack (void)
3690 {
3691   ClutterMainContext *context = _clutter_context_get_default ();
3692
3693   if (context->shaders != NULL)
3694     return context->shaders->data;
3695
3696   return NULL;
3697 }
3698
3699 ClutterActor *
3700 _clutter_context_pop_shader_stack (ClutterActor *actor)
3701 {
3702   ClutterMainContext *context = _clutter_context_get_default ();
3703
3704   context->shaders = g_slist_remove (context->shaders, actor);
3705
3706   return _clutter_context_peek_shader_stack ();
3707 }
3708
3709 gboolean
3710 _clutter_context_get_motion_events_enabled (void)
3711 {
3712   ClutterMainContext *context = _clutter_context_get_default ();
3713
3714   return context->motion_events_per_actor;
3715 }
3716
3717 /**
3718  * clutter_check_windowing_backend:
3719  * @backend_type: the name of the backend to check
3720  *
3721  * Checks the run-time name of the Clutter windowing system backend, using
3722  * the symbolic macros like %CLUTTER_WINDOWING_WIN32 or
3723  * %CLUTTER_WINDOWING_X11.
3724  *
3725  * This function should be used in conjuction with the compile-time macros
3726  * inside applications and libraries that are using the platform-specific
3727  * windowing system API, to ensure that they are running on the correct
3728  * windowing system; for instance:
3729  *
3730  * |[
3731  * &num;ifdef CLUTTER_WINDOWING_X11
3732  *   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
3733  *     {
3734  *       /&ast; it is safe to use the clutter_x11_* API &ast;/
3735  *     }
3736  *   else
3737  * &num;endif
3738  * &num;ifdef CLUTTER_WINDOWING_WIN32
3739  *   if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32))
3740  *     {
3741  *       /&ast; it is safe to use the clutter_win32_* API &ast;/
3742  *     }
3743  *   else
3744  * &num;endif
3745  *     g_error ("Unknown Clutter backend.");
3746  * ]|
3747  *
3748  * Return value: %TRUE if the current Clutter windowing system backend is
3749  *   the one checked, and %FALSE otherwise
3750  *
3751  * Since: 1.10
3752  */
3753 gboolean
3754 clutter_check_windowing_backend (const char *backend_type)
3755 {
3756   ClutterMainContext *context = _clutter_context_get_default ();
3757
3758   g_return_val_if_fail (backend_type != NULL, FALSE);
3759
3760   backend_type = g_intern_string (backend_type);
3761
3762 #ifdef CLUTTER_WINDOWING_OSX
3763   if (backend_type == I_(CLUTTER_WINDOWING_OSX) &&
3764       CLUTTER_IS_BACKEND_OSX (context->backend))
3765     return TRUE;
3766   else
3767 #endif
3768 #ifdef CLUTTER_WINDOWING_WIN32
3769   if (backend_type == I_(CLUTTER_WINDOWING_WIN32) &&
3770       CLUTTER_IS_BACKEND_WIN32 (context->backend))
3771     return TRUE;
3772   else
3773 #endif
3774 #ifdef CLUTTER_WINDOWING_WAYLAND
3775   if (backend_type == I_(CLUTTER_WINDOWING_WAYLAND) &&
3776       CLUTTER_IS_BACKEND_WAYLAND (context->backend))
3777     return TRUE;
3778   else
3779 #endif
3780 #ifdef CLUTTER_WINDOWING_EGL
3781   if (backend_type == I_(CLUTTER_WINDOWING_EGL) &&
3782       CLUTTER_IS_BACKEND_EGL_NATIVE (context->backend))
3783     return TRUE;
3784   else
3785 #endif
3786 #ifdef CLUTTER_WINDOWING_GDK
3787   if (backend_type == I_(CLUTTER_WINDOWING_GDK) &&
3788       CLUTTER_IS_BACKEND_GDK (context->backend))
3789     return TRUE;
3790   else
3791 #endif
3792 #ifdef CLUTTER_WINDOWING_X11
3793   if (backend_type == I_(CLUTTER_WINDOWING_X11) &&
3794       CLUTTER_IS_BACKEND_X11 (context->backend))
3795     return TRUE;
3796   else
3797 #endif
3798   return FALSE;
3799 }
3800
3801 gboolean
3802 _clutter_get_sync_to_vblank (void)
3803 {
3804   return clutter_sync_to_vblank;
3805 }
3806
3807 void
3808 _clutter_debug_messagev (const char *format,
3809                          va_list     var_args)
3810 {
3811   gchar *stamp, *fmt;
3812
3813   stamp = g_strdup_printf ("[%16" G_GINT64_FORMAT "]",
3814                            g_get_monotonic_time ());
3815   fmt = g_strconcat (stamp, ":", format, NULL);
3816   g_free (stamp);
3817
3818   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, var_args);
3819
3820 #ifdef CLUTTER_ENABLE_PROFILE
3821   if (_clutter_uprof_context != NULL)
3822     uprof_context_vtrace_message (_clutter_uprof_context, format, var_args);
3823 #endif
3824
3825   g_free (fmt);
3826 }
3827
3828 void
3829 _clutter_debug_message (const char *format, ...)
3830 {
3831   va_list args;
3832
3833   va_start (args, format);
3834   _clutter_debug_messagev (format, args);
3835   va_end (args);
3836 }
3837
3838 gboolean
3839 _clutter_diagnostic_enabled (void)
3840 {
3841   static const char *clutter_enable_diagnostic = NULL;
3842
3843   if (G_UNLIKELY (clutter_enable_diagnostic == NULL))
3844     {
3845       clutter_enable_diagnostic = g_getenv ("CLUTTER_ENABLE_DIAGNOSTIC");
3846
3847       if (clutter_enable_diagnostic == NULL)
3848         clutter_enable_diagnostic = "0";
3849     }
3850
3851   return *clutter_enable_diagnostic != '0';
3852 }
3853
3854 void
3855 _clutter_diagnostic_message (const char *format, ...)
3856 {
3857   va_list args;
3858   char *fmt;
3859
3860   fmt = g_strconcat ("[DIAGNOSTIC]: ", format, NULL);
3861
3862   va_start (args, format);
3863   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, args);
3864   va_end (args);
3865
3866   g_free (fmt);
3867 }