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