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