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