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