123caeb0914b878b232d6538a5dd1db7e657b820
[profile/ivi/clutter.git] / clutter / clutter-stage.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22  *
23  *
24  */
25
26 /**
27  * SECTION:clutter-stage
28  * @short_description: Top level visual element to which actors are placed.
29  *
30  * #ClutterStage is a top level 'window' on which child actors are placed
31  * and manipulated.
32  *
33  * Backends might provide support for multiple stages. The support for this
34  * feature can be checked at run-time using the clutter_feature_available()
35  * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
36  * supports multiple stages, new #ClutterStage instances can be created
37  * using clutter_stage_new(). These stages must be managed by the developer
38  * using clutter_actor_destroy(), which will take care of destroying all the
39  * actors contained inside them.
40  *
41  * #ClutterStage is a proxy actor, wrapping the backend-specific
42  * implementation of the windowing system. It is possible to subclass
43  * #ClutterStage, as long as every overridden virtual function chains up to
44  * the parent class corresponding function.
45  */
46
47 #ifdef HAVE_CONFIG_H
48 #include "config.h"
49 #endif
50
51 #include <math.h>
52 #include <cairo.h>
53
54 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
55
56 #include "clutter-stage.h"
57 #include "deprecated/clutter-stage.h"
58 #include "deprecated/clutter-container.h"
59
60 #include "clutter-actor-private.h"
61 #include "clutter-backend-private.h"
62 #include "clutter-cairo-texture.h"
63 #include "clutter-color.h"
64 #include "clutter-container.h"
65 #include "clutter-debug.h"
66 #include "clutter-device-manager-private.h"
67 #include "clutter-enum-types.h"
68 #include "clutter-event-private.h"
69 #include "clutter-id-pool.h"
70 #include "clutter-main.h"
71 #include "clutter-marshal.h"
72 #include "clutter-master-clock.h"
73 #include "clutter-paint-volume-private.h"
74 #include "clutter-private.h"
75 #include "clutter-profile.h"
76 #include "clutter-stage-manager-private.h"
77 #include "clutter-stage-private.h"
78 #include "clutter-util.h"
79 #include "clutter-version.h"    /* For flavour */
80 #include "clutter-private.h"
81
82 #include "cogl/cogl.h"
83
84 static void clutter_container_iface_init (ClutterContainerIface *iface);
85
86 G_DEFINE_TYPE_WITH_CODE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP,
87                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
88                                                 clutter_container_iface_init))
89
90 #define CLUTTER_STAGE_GET_PRIVATE(obj) \
91 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_STAGE, ClutterStagePrivate))
92
93 /* <private>
94  * ClutterStageHint:
95  * @CLUTTER_STAGE_NONE: No hint set
96  * @CLUTTER_STAGE_NO_CLEAR_ON_PAINT: When this hint is set, the stage
97  *   should not clear the viewport; this flag is useful when painting
98  *   fully opaque actors covering the whole visible area of the stage,
99  *   i.e. when no blending with the stage color happens over the whole
100  *   stage viewport
101  *
102  * A series of hints that enable or disable behaviours on the stage
103  */
104 typedef enum { /*< prefix=CLUTTER_STAGE >*/
105   CLUTTER_STAGE_HINT_NONE = 0,
106
107   CLUTTER_STAGE_NO_CLEAR_ON_PAINT = 1 << 0
108 } ClutterStageHint;
109
110 #define STAGE_NO_CLEAR_ON_PAINT(s)      ((((ClutterStage *) (s))->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0)
111
112 struct _ClutterStageQueueRedrawEntry
113 {
114   ClutterActor *actor;
115   gboolean has_clip;
116   ClutterPaintVolume clip;
117 };
118
119 struct _ClutterStagePrivate
120 {
121   /* the stage implementation */
122   ClutterStageWindow *impl;
123
124   ClutterPerspective perspective;
125   CoglMatrix projection;
126   CoglMatrix inverse_projection;
127   CoglMatrix view;
128   float viewport[4];
129
130   ClutterFog fog;
131
132   gchar *title;
133   ClutterActor *key_focused_actor;
134
135   GQueue *event_queue;
136
137   ClutterStageHint stage_hints;
138
139   gint picks_per_frame;
140
141   GArray *paint_volume_stack;
142
143   ClutterPlane current_clip_planes[4];
144
145   GList *pending_queue_redraws;
146
147   ClutterPickMode pick_buffer_mode;
148
149   CoglFramebuffer *active_framebuffer;
150
151   GHashTable *devices;
152
153   GTimer *fps_timer;
154   gint32 timer_n_frames;
155
156   ClutterIDPool *pick_id_pool;
157
158 #ifdef CLUTTER_ENABLE_DEBUG
159   gulong redraw_count;
160 #endif /* CLUTTER_ENABLE_DEBUG */
161
162   ClutterStageState current_state;
163
164   guint relayout_pending       : 1;
165   guint redraw_pending         : 1;
166   guint is_fullscreen          : 1;
167   guint is_cursor_visible      : 1;
168   guint is_user_resizable      : 1;
169   guint use_fog                : 1;
170   guint throttle_motion_events : 1;
171   guint use_alpha              : 1;
172   guint min_size_changed       : 1;
173   guint dirty_viewport         : 1;
174   guint dirty_projection       : 1;
175   guint have_valid_pick_buffer : 1;
176   guint accept_focus           : 1;
177   guint motion_events_enabled  : 1;
178   guint has_custom_perspective : 1;
179 };
180
181 enum
182 {
183   PROP_0,
184
185   PROP_COLOR,
186   PROP_FULLSCREEN_SET,
187   PROP_OFFSCREEN,
188   PROP_CURSOR_VISIBLE,
189   PROP_PERSPECTIVE,
190   PROP_TITLE,
191   PROP_USER_RESIZABLE,
192   PROP_USE_FOG,
193   PROP_FOG,
194   PROP_USE_ALPHA,
195   PROP_KEY_FOCUS,
196   PROP_NO_CLEAR_HINT,
197   PROP_ACCEPT_FOCUS
198 };
199
200 enum
201 {
202   FULLSCREEN,
203   UNFULLSCREEN,
204   ACTIVATE,
205   DEACTIVATE,
206   DELETE_EVENT,
207
208   LAST_SIGNAL
209 };
210
211 static guint stage_signals[LAST_SIGNAL] = { 0, };
212
213 static const ClutterColor default_stage_color = { 255, 255, 255, 255 };
214
215 static void _clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage);
216
217 static void
218 clutter_stage_real_add (ClutterContainer *container,
219                         ClutterActor     *child)
220 {
221   clutter_actor_add_child (CLUTTER_ACTOR (container), child);
222 }
223
224 static void
225 clutter_stage_real_remove (ClutterContainer *container,
226                            ClutterActor     *child)
227 {
228   clutter_actor_remove_child (CLUTTER_ACTOR (container), child);
229 }
230
231 static void
232 clutter_stage_real_foreach (ClutterContainer *container,
233                             ClutterCallback   callback,
234                             gpointer          user_data)
235 {
236   ClutterActorIter iter;
237   ClutterActor *child;
238
239   clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
240
241   while (clutter_actor_iter_next (&iter, &child))
242     callback (child, user_data);
243 }
244
245 static void
246 clutter_stage_real_raise (ClutterContainer *container,
247                           ClutterActor     *child,
248                           ClutterActor     *sibling)
249 {
250   clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (container),
251                                          child,
252                                          sibling);
253 }
254
255 static void
256 clutter_stage_real_lower (ClutterContainer *container,
257                           ClutterActor     *child,
258                           ClutterActor     *sibling)
259 {
260   clutter_actor_set_child_below_sibling (CLUTTER_ACTOR (container),
261                                          child,
262                                          sibling);
263 }
264
265 static void
266 clutter_stage_real_sort_depth_order (ClutterContainer *container)
267 {
268 }
269
270 static void
271 clutter_container_iface_init (ClutterContainerIface *iface)
272 {
273   iface->add = clutter_stage_real_add;
274   iface->remove = clutter_stage_real_remove;
275   iface->foreach = clutter_stage_real_foreach;
276   iface->raise = clutter_stage_real_raise;
277   iface->lower = clutter_stage_real_lower;
278   iface->sort_depth_order = clutter_stage_real_sort_depth_order;
279 }
280
281 static void
282 clutter_stage_get_preferred_width (ClutterActor *self,
283                                    gfloat        for_height,
284                                    gfloat       *min_width_p,
285                                    gfloat       *natural_width_p)
286 {
287   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
288   cairo_rectangle_int_t geom;
289
290   if (priv->impl == NULL)
291     return;
292
293   _clutter_stage_window_get_geometry (priv->impl, &geom);
294
295   if (min_width_p)
296     *min_width_p = geom.width;
297
298   if (natural_width_p)
299     *natural_width_p = geom.width;
300 }
301
302 static void
303 clutter_stage_get_preferred_height (ClutterActor *self,
304                                     gfloat        for_width,
305                                     gfloat       *min_height_p,
306                                     gfloat       *natural_height_p)
307 {
308   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
309   cairo_rectangle_int_t geom;
310
311   if (priv->impl == NULL)
312     return;
313
314   _clutter_stage_window_get_geometry (priv->impl, &geom);
315
316   if (min_height_p)
317     *min_height_p = geom.height;
318
319   if (natural_height_p)
320     *natural_height_p = geom.height;
321 }
322
323 static inline void
324 queue_full_redraw (ClutterStage *stage)
325 {
326   ClutterStageWindow *stage_window;
327
328   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
329     return;
330
331   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
332
333   /* Just calling clutter_actor_queue_redraw will typically only
334    * redraw the bounding box of the children parented on the stage but
335    * in this case we really need to ensure that the full stage is
336    * redrawn so we add a NULL redraw clip to the stage window. */
337   stage_window = _clutter_stage_get_window (stage);
338   if (stage_window == NULL)
339     return;
340
341   _clutter_stage_window_add_redraw_clip (stage_window, NULL);
342 }
343
344 static gboolean
345 stage_is_default (ClutterStage *stage)
346 {
347   ClutterStageManager *stage_manager;
348   ClutterStageWindow *impl;
349
350   stage_manager = clutter_stage_manager_get_default ();
351   if (stage != clutter_stage_manager_get_default_stage (stage_manager))
352     return FALSE;
353
354   impl = _clutter_stage_get_window (stage);
355   if (impl != _clutter_stage_get_default_window ())
356     return FALSE;
357
358   return TRUE;
359 }
360
361 static void
362 clutter_stage_allocate (ClutterActor           *self,
363                         const ClutterActorBox  *box,
364                         ClutterAllocationFlags  flags)
365 {
366   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
367   ClutterGeometry prev_geom, geom;
368   cairo_rectangle_int_t window_size;
369   gboolean origin_changed;
370   gint width, height;
371
372   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)
373                  ? TRUE
374                  : FALSE;
375
376   if (priv->impl == NULL)
377     return;
378
379   /* our old allocation */
380   clutter_actor_get_allocation_geometry (self, &prev_geom);
381
382   /* the current allocation */
383   width = clutter_actor_box_get_width (box);
384   height = clutter_actor_box_get_height (box);
385
386   /* the current Stage implementation size */
387   _clutter_stage_window_get_geometry (priv->impl, &window_size);
388
389   /* if the stage is fixed size (for instance, it's using a EGL framebuffer)
390    * then we simply ignore any allocation request and override the
391    * allocation chain - because we cannot forcibly change the size of the
392    * stage window.
393    */
394   if ((!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC)))
395     {
396       CLUTTER_NOTE (LAYOUT,
397                     "Following allocation to %dx%d (origin %s)",
398                     width, height,
399                     origin_changed ? "changed" : "not changed");
400
401       clutter_actor_set_allocation (self, box,
402                                     flags | CLUTTER_DELEGATE_LAYOUT);
403
404       /* Ensure the window is sized correctly */
405       if (!priv->is_fullscreen)
406         {
407           if (priv->min_size_changed)
408             {
409               gfloat min_width, min_height;
410               gboolean min_width_set, min_height_set;
411
412               g_object_get (G_OBJECT (self),
413                             "min-width", &min_width,
414                             "min-width-set", &min_width_set,
415                             "min-height", &min_height,
416                             "min-height-set", &min_height_set,
417                             NULL);
418
419               if (!min_width_set)
420                 min_width = 1;
421               if (!min_height_set)
422                 min_height = 1;
423
424               if (width < min_width)
425                 width = min_width;
426               if (height < min_height)
427                 height = min_height;
428
429               priv->min_size_changed = FALSE;
430             }
431
432           if (window_size.width != width ||
433               window_size.height != height)
434             {
435               _clutter_stage_window_resize (priv->impl, width, height);
436             }
437         }
438     }
439   else
440     {
441       ClutterActorBox override = { 0, };
442
443       /* override the passed allocation */
444       override.x1 = 0;
445       override.y1 = 0;
446       override.x2 = window_size.width;
447       override.y2 = window_size.height;
448
449       CLUTTER_NOTE (LAYOUT,
450                     "Overrigin original allocation of %dx%d "
451                     "with %dx%d (origin %s)",
452                     width, height,
453                     (int) (override.x2),
454                     (int) (override.y2),
455                     origin_changed ? "changed" : "not changed");
456
457       /* and store the overridden allocation */
458       clutter_actor_set_allocation (self, &override,
459                                     flags | CLUTTER_DELEGATE_LAYOUT);
460     }
461
462   /* XXX: Until Cogl becomes fully responsible for backend windows
463    * Clutter need to manually keep it informed of the current window
464    * size. We do this after the allocation above so that the stage
465    * window has a chance to update the window size based on the
466    * allocation.
467    */
468   _clutter_stage_window_get_geometry (priv->impl, &window_size);
469   cogl_onscreen_clutter_backend_set_size (window_size.width,
470                                           window_size.height);
471
472   /* reset the viewport if the allocation effectively changed */
473   clutter_actor_get_allocation_geometry (self, &geom);
474   if (geom.width != prev_geom.width ||
475       geom.height != prev_geom.height)
476     {
477       _clutter_stage_set_viewport (CLUTTER_STAGE (self),
478                                    0, 0,
479                                    geom.width,
480                                    geom.height);
481
482       /* Note: we don't assume that set_viewport will queue a full redraw
483        * since it may bail-out early if something preemptively set the
484        * viewport before the stage was really allocated its new size.
485        */
486       queue_full_redraw (CLUTTER_STAGE (self));
487     }
488 }
489
490 typedef struct _Vector4
491 {
492   float x, y, z, w;
493 } Vector4;
494
495 static void
496 _cogl_util_get_eye_planes_for_screen_poly (float *polygon,
497                                            int n_vertices,
498                                            float *viewport,
499                                            const CoglMatrix *projection,
500                                            const CoglMatrix *inverse_project,
501                                            ClutterPlane *planes)
502 {
503   float Wc;
504   Vector4 *tmp_poly;
505   ClutterPlane *plane;
506   int i;
507   float b[3];
508   float c[3];
509   int count;
510
511   tmp_poly = g_alloca (sizeof (Vector4) * n_vertices * 2);
512
513 #define DEPTH -50
514
515   /* Determine W in clip-space (Wc) for a point (0, 0, DEPTH, 1)
516    *
517    * Note: the depth could be anything except 0.
518    *
519    * We will transform the polygon into clip coordinates using this
520    * depth and then into eye coordinates. Our clip planes will be
521    * defined by triangles that extend between points of the polygon at
522    * DEPTH and corresponding points of the same polygon at DEPTH * 2.
523    *
524    * NB: Wc defines the position of the clip planes in clip
525    * coordinates. Given a screen aligned cross section through the
526    * frustum; coordinates range from [-Wc,Wc] left to right on the
527    * x-axis and [Wc,-Wc] top to bottom on the y-axis.
528    */
529   Wc = DEPTH * projection->wz + projection->ww;
530
531 #define CLIP_X(X) ((((float)X - viewport[0]) * (2.0 / viewport[2])) - 1) * Wc
532 #define CLIP_Y(Y) ((((float)Y - viewport[1]) * (2.0 / viewport[3])) - 1) * -Wc
533
534   for (i = 0; i < n_vertices; i++)
535     {
536       tmp_poly[i].x = CLIP_X (polygon[i * 2]);
537       tmp_poly[i].y = CLIP_Y (polygon[i * 2 + 1]);
538       tmp_poly[i].z = DEPTH;
539       tmp_poly[i].w = Wc;
540     }
541
542   Wc = DEPTH * 2 * projection->wz + projection->ww;
543
544   /* FIXME: technically we don't need to project all of the points
545    * twice, it would be enough project every other point since
546    * we can share points in this set to define the plane vectors. */
547   for (i = 0; i < n_vertices; i++)
548     {
549       tmp_poly[n_vertices + i].x = CLIP_X (polygon[i * 2]);
550       tmp_poly[n_vertices + i].y = CLIP_Y (polygon[i * 2 + 1]);
551       tmp_poly[n_vertices + i].z = DEPTH * 2;
552       tmp_poly[n_vertices + i].w = Wc;
553     }
554
555 #undef CLIP_X
556 #undef CLIP_Y
557
558   cogl_matrix_project_points (inverse_project,
559                               4,
560                               sizeof (Vector4),
561                               tmp_poly,
562                               sizeof (Vector4),
563                               tmp_poly,
564                               n_vertices * 2);
565
566   /* XXX: It's quite ugly that we end up with these casts between
567    * Vector4 types and CoglVector3s, it might be better if the
568    * cogl_vector APIs just took pointers to floats.
569    */
570
571   count = n_vertices - 1;
572   for (i = 0; i < count; i++)
573     {
574       plane = &planes[i];
575       memcpy (plane->v0, tmp_poly + i, sizeof (float) * 3);
576       memcpy (b, tmp_poly + n_vertices + i, sizeof (float) * 3);
577       memcpy (c, tmp_poly + n_vertices + i + 1, sizeof (float) * 3);
578       cogl_vector3_subtract (b, b, plane->v0);
579       cogl_vector3_subtract (c, c, plane->v0);
580       cogl_vector3_cross_product (plane->n, b, c);
581       cogl_vector3_normalize (plane->n);
582     }
583
584   plane = &planes[n_vertices - 1];
585   memcpy (plane->v0, tmp_poly + 0, sizeof (float) * 3);
586   memcpy (b, tmp_poly + (2 * n_vertices - 1), sizeof (float) * 3);
587   memcpy (c, tmp_poly + n_vertices, sizeof (float) * 3);
588   cogl_vector3_subtract (b, b, plane->v0);
589   cogl_vector3_subtract (c, c, plane->v0);
590   cogl_vector3_cross_product (plane->n, b, c);
591   cogl_vector3_normalize (plane->n);
592 }
593
594 static void
595 _clutter_stage_update_active_framebuffer (ClutterStage *stage)
596 {
597   ClutterStagePrivate *priv = stage->priv;
598
599   /* We track the CoglFramebuffer that corresponds to the stage itself
600    * so, for example, we can disable culling when rendering to an
601    * offscreen framebuffer.
602    */
603
604   priv->active_framebuffer =
605     _clutter_stage_window_get_active_framebuffer (priv->impl);
606
607   if (!priv->active_framebuffer)
608     priv->active_framebuffer = cogl_get_draw_framebuffer ();
609 }
610
611 /* This provides a common point of entry for painting the scenegraph
612  * for picking or painting...
613  *
614  * XXX: Instead of having a toplevel 2D clip region, it might be
615  * better to have a clip volume within the view frustum. This could
616  * allow us to avoid projecting actors into window coordinates to
617  * be able to cull them.
618  */
619 void
620 _clutter_stage_do_paint (ClutterStage                *stage,
621                          const cairo_rectangle_int_t *clip)
622 {
623   ClutterStagePrivate *priv = stage->priv;
624   float clip_poly[8];
625   cairo_rectangle_int_t geom;
626
627   _clutter_stage_window_get_geometry (priv->impl, &geom);
628
629   if (clip)
630     {
631       clip_poly[0] = MAX (clip->x, 0);
632       clip_poly[1] = MAX (clip->y, 0);
633       clip_poly[2] = MIN (clip->x + clip->width, geom.width);
634       clip_poly[3] = clip_poly[1];
635       clip_poly[4] = clip_poly[2];
636       clip_poly[5] = MIN (clip->y + clip->height, geom.height);
637       clip_poly[6] = clip_poly[0];
638       clip_poly[7] = clip_poly[5];
639     }
640   else
641     {
642       clip_poly[0] = 0;
643       clip_poly[1] = 0;
644       clip_poly[2] = geom.width;
645       clip_poly[3] = 0;
646       clip_poly[4] = geom.width;
647       clip_poly[5] = geom.height;
648       clip_poly[6] = 0;
649       clip_poly[7] = geom.height;
650     }
651
652   CLUTTER_NOTE (CLIPPING, "Setting stage clip too: "
653                 "x=%f, y=%f, width=%f, height=%f",
654                 clip_poly[0], clip_poly[1],
655                 clip_poly[2] - clip_poly[0],
656                 clip_poly[5] - clip_poly[1]);
657
658   _cogl_util_get_eye_planes_for_screen_poly (clip_poly,
659                                              4,
660                                              priv->viewport,
661                                              &priv->projection,
662                                              &priv->inverse_projection,
663                                              priv->current_clip_planes);
664
665   _clutter_stage_paint_volume_stack_free_all (stage);
666   _clutter_stage_update_active_framebuffer (stage);
667   clutter_actor_paint (CLUTTER_ACTOR (stage));
668 }
669
670 static void
671 clutter_stage_paint (ClutterActor *self)
672 {
673   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
674   CoglBufferBit clear_flags;
675   ClutterColor bg_color;
676   CoglColor stage_color;
677   ClutterActorIter iter;
678   ClutterActor *child;
679   guint8 real_alpha;
680
681   CLUTTER_STATIC_TIMER (stage_clear_timer,
682                         "Painting actors", /* parent */
683                         "Stage clear",
684                         "The time spent clearing the stage",
685                         0 /* no application private data */);
686
687   CLUTTER_NOTE (PAINT, "Initializing stage paint");
688
689   /* composite the opacity to the stage color */
690   clutter_actor_get_background_color (self, &bg_color);
691   real_alpha = clutter_actor_get_opacity (self)
692              * bg_color.alpha
693              / 255;
694
695   clear_flags = COGL_BUFFER_BIT_DEPTH;
696   if (!STAGE_NO_CLEAR_ON_PAINT (self))
697     clear_flags |= COGL_BUFFER_BIT_COLOR;
698
699   cogl_disable_fog ();
700
701   CLUTTER_TIMER_START (_clutter_uprof_context, stage_clear_timer);
702   /* we use the real alpha to clear the stage if :use-alpha is
703    * set; the effect depends entirely on the Clutter backend
704    */
705   cogl_color_init_from_4ub (&stage_color,
706                             bg_color.red,
707                             bg_color.green,
708                             bg_color.blue,
709                             priv->use_alpha ? real_alpha : 255);
710   cogl_color_premultiply (&stage_color);
711   cogl_clear (&stage_color, clear_flags);
712   CLUTTER_TIMER_STOP (_clutter_uprof_context, stage_clear_timer);
713
714   clutter_actor_iter_init (&iter, self);
715   while (clutter_actor_iter_next (&iter, &child))
716     clutter_actor_paint (child);
717 }
718
719 static void
720 clutter_stage_pick (ClutterActor       *self,
721                     const ClutterColor *color)
722 {
723   ClutterActorIter iter;
724   ClutterActor *child;
725
726   /* Note: we don't chain up to our parent as we don't want any geometry
727    * emitted for the stage itself. The stage's pick id is effectively handled
728    * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async()
729    */
730   clutter_actor_iter_init (&iter, self);
731   while (clutter_actor_iter_next (&iter, &child))
732     clutter_actor_paint (child);
733 }
734
735 static gboolean
736 clutter_stage_get_paint_volume (ClutterActor *self,
737                                 ClutterPaintVolume *volume)
738 {
739   /* Returning False effectively means Clutter has to assume it covers
740    * everything... */
741   return FALSE;
742 }
743
744 static void
745 clutter_stage_realize (ClutterActor *self)
746 {
747   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
748   gboolean is_realized;
749
750   /* Make sure the viewport and projection matrix are valid for the
751    * first paint (which will likely occur before the ConfigureNotify
752    * is received)
753    */
754   priv->dirty_viewport = TRUE;
755   priv->dirty_projection = TRUE;
756
757   g_assert (priv->impl != NULL);
758   is_realized = _clutter_stage_window_realize (priv->impl);
759
760   /* ensure that the stage is using the context if the
761    * realization sequence was successful
762    */
763   if (is_realized)
764     {
765       ClutterBackend *backend = clutter_get_default_backend ();
766
767       /* We want to select the context without calling
768          clutter_backend_ensure_context so that it doesn't call any
769          Cogl functions. Otherwise it would create the Cogl context
770          before we get a chance to check whether the GL version is
771          valid */
772       _clutter_backend_ensure_context_internal (backend, CLUTTER_STAGE (self));
773     }
774   else
775     CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
776 }
777
778 static void
779 clutter_stage_unrealize (ClutterActor *self)
780 {
781   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
782
783   /* and then unrealize the implementation */
784   g_assert (priv->impl != NULL);
785   _clutter_stage_window_unrealize (priv->impl);
786
787   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
788
789   clutter_stage_ensure_current (CLUTTER_STAGE (self));
790 }
791
792 static void
793 clutter_stage_show_all (ClutterActor *self)
794 {
795   ClutterActorIter iter;
796   ClutterActor *child;
797
798   /* we don't do a recursive show_all(), to maintain the old
799    * invariants from ClutterGroup
800    */
801   clutter_actor_iter_init (&iter, self);
802   while (clutter_actor_iter_next (&iter, &child))
803     clutter_actor_show (child);
804
805   clutter_actor_show (self);
806 }
807
808 static void
809 clutter_stage_show (ClutterActor *self)
810 {
811   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
812
813   CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);
814
815   /* Possibly do an allocation run so that the stage will have the
816      right size before we map it */
817   _clutter_stage_maybe_relayout (self);
818
819   g_assert (priv->impl != NULL);
820   _clutter_stage_window_show (priv->impl, TRUE);
821 }
822
823 static void
824 clutter_stage_hide_all (ClutterActor *self)
825 {
826   ClutterActorIter iter;
827   ClutterActor *child;
828
829   clutter_actor_hide (self);
830
831   /* we don't do a recursive hide_all(), to maintain the old invariants
832    * from ClutterGroup
833    */
834   clutter_actor_iter_init (&iter, self);
835   while (clutter_actor_iter_next (&iter, &child))
836     clutter_actor_hide (child);
837 }
838
839 static void
840 clutter_stage_hide (ClutterActor *self)
841 {
842   ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
843
844   g_assert (priv->impl != NULL);
845   _clutter_stage_window_hide (priv->impl);
846
847   CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
848 }
849
850 static void
851 clutter_stage_emit_key_focus_event (ClutterStage *stage,
852                                     gboolean      focus_in)
853 {
854   ClutterStagePrivate *priv = stage->priv;
855
856   if (priv->key_focused_actor == NULL)
857     return;
858
859   if (focus_in)
860     g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
861   else
862     g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
863
864   g_object_notify (G_OBJECT (stage), "key-focus");
865 }
866
867 static void
868 clutter_stage_real_activate (ClutterStage *stage)
869 {
870   clutter_stage_emit_key_focus_event (stage, TRUE);
871 }
872
873 static void
874 clutter_stage_real_deactivate (ClutterStage *stage)
875 {
876   clutter_stage_emit_key_focus_event (stage, FALSE);
877 }
878
879 static void
880 clutter_stage_real_fullscreen (ClutterStage *stage)
881 {
882   ClutterStagePrivate *priv = stage->priv;
883   cairo_rectangle_int_t geom;
884   ClutterActorBox box;
885
886   /* we need to force an allocation here because the size
887    * of the stage might have been changed by the backend
888    *
889    * this is a really bad solution to the issues caused by
890    * the fact that fullscreening the stage on the X11 backends
891    * is really an asynchronous operation
892    */
893   _clutter_stage_window_get_geometry (priv->impl, &geom);
894
895   box.x1 = 0;
896   box.y1 = 0;
897   box.x2 = geom.width;
898   box.y2 = geom.height;
899
900   clutter_actor_allocate (CLUTTER_ACTOR (stage),
901                           &box,
902                           CLUTTER_ALLOCATION_NONE);
903 }
904
905 void
906 _clutter_stage_queue_event (ClutterStage *stage,
907                             ClutterEvent *event)
908 {
909   ClutterStagePrivate *priv;
910   gboolean first_event;
911   ClutterInputDevice *device;
912
913   g_return_if_fail (CLUTTER_IS_STAGE (stage));
914
915   priv = stage->priv;
916
917   first_event = priv->event_queue->length == 0;
918
919   g_queue_push_tail (priv->event_queue, clutter_event_copy (event));
920
921   if (first_event)
922     {
923       ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
924       _clutter_master_clock_start_running (master_clock);
925     }
926
927   /* if needed, update the state of the input device of the event.
928    * we do it here to avoid calling the same code from every backend
929    * event processing function
930    */
931   device = clutter_event_get_device (event);
932   if (device != NULL)
933     {
934       ClutterModifierType event_state = clutter_event_get_state (event);
935       guint32 event_time = clutter_event_get_time (event);
936       gfloat event_x, event_y;
937
938       clutter_event_get_coords (event, &event_x, &event_y);
939
940       _clutter_input_device_set_coords (device, event_x, event_y);
941       _clutter_input_device_set_state (device, event_state);
942       _clutter_input_device_set_time (device, event_time);
943     }
944 }
945
946 gboolean
947 _clutter_stage_has_queued_events (ClutterStage *stage)
948 {
949   ClutterStagePrivate *priv;
950
951   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
952
953   priv = stage->priv;
954
955   return priv->event_queue->length > 0;
956 }
957
958 void
959 _clutter_stage_process_queued_events (ClutterStage *stage)
960 {
961   ClutterStagePrivate *priv;
962   GList *events, *l;
963
964   g_return_if_fail (CLUTTER_IS_STAGE (stage));
965
966   priv = stage->priv;
967
968   if (priv->event_queue->length == 0)
969     return;
970
971   /* In case the stage gets destroyed during event processing */
972   g_object_ref (stage);
973
974   /* Steal events before starting processing to avoid reentrancy
975    * issues */
976   events = priv->event_queue->head;
977   priv->event_queue->head =  NULL;
978   priv->event_queue->tail = NULL;
979   priv->event_queue->length = 0;
980
981   for (l = events; l != NULL; l = l->next)
982     {
983       ClutterEvent *event;
984       ClutterEvent *next_event;
985       ClutterInputDevice *device;
986       ClutterInputDevice *next_device;
987       gboolean check_device = FALSE;
988
989       event = l->data;
990       next_event = l->next ? l->next->data : NULL;
991
992       device = clutter_event_get_device (event);
993
994       if (next_event != NULL)
995         next_device = clutter_event_get_device (next_event);
996       else
997         next_device = NULL;
998
999       if (device != NULL && next_device != NULL)
1000         check_device = TRUE;
1001
1002       /* Skip consecutive motion events coming from the same device */
1003       if (priv->throttle_motion_events &&
1004           next_event != NULL &&
1005           event->type == CLUTTER_MOTION &&
1006           (next_event->type == CLUTTER_MOTION ||
1007            next_event->type == CLUTTER_LEAVE) &&
1008           (!check_device || (device == next_device)))
1009         {
1010           CLUTTER_NOTE (EVENT,
1011                         "Omitting motion event at %d, %d",
1012                         (int) event->motion.x,
1013                         (int) event->motion.y);
1014           goto next_event;
1015         }
1016
1017       _clutter_process_event (event);
1018
1019     next_event:
1020       clutter_event_free (event);
1021     }
1022
1023   g_list_free (events);
1024
1025   g_object_unref (stage);
1026 }
1027
1028 /**
1029  * _clutter_stage_needs_update:
1030  * @stage: A #ClutterStage
1031  *
1032  * Determines if _clutter_stage_do_update() needs to be called.
1033  *
1034  * Return value: %TRUE if the stage need layout or painting
1035  */
1036 gboolean
1037 _clutter_stage_needs_update (ClutterStage *stage)
1038 {
1039   ClutterStagePrivate *priv;
1040
1041   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
1042
1043   priv = stage->priv;
1044
1045   return priv->relayout_pending || priv->redraw_pending;
1046 }
1047
1048 void
1049 _clutter_stage_maybe_relayout (ClutterActor *actor)
1050 {
1051   ClutterStage *stage = CLUTTER_STAGE (actor);
1052   ClutterStagePrivate *priv = stage->priv;
1053   gfloat natural_width, natural_height;
1054   ClutterActorBox box = { 0, };
1055   CLUTTER_STATIC_TIMER (relayout_timer,
1056                         "Mainloop", /* no parent */
1057                         "Layouting",
1058                         "The time spent reallocating the stage",
1059                         0 /* no application private data */);
1060
1061   if (!priv->relayout_pending)
1062     return;
1063
1064   /* avoid reentrancy */
1065   if (!CLUTTER_ACTOR_IN_RELAYOUT (stage))
1066     {
1067       priv->relayout_pending = FALSE;
1068
1069       CLUTTER_TIMER_START (_clutter_uprof_context, relayout_timer);
1070       CLUTTER_NOTE (ACTOR, "Recomputing layout");
1071
1072       CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
1073
1074       natural_width = natural_height = 0;
1075       clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage),
1076                                         NULL, NULL,
1077                                         &natural_width, &natural_height);
1078
1079       box.x1 = 0;
1080       box.y1 = 0;
1081       box.x2 = natural_width;
1082       box.y2 = natural_height;
1083
1084       CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
1085                     (int) natural_width,
1086                     (int) natural_height);
1087
1088       clutter_actor_allocate (CLUTTER_ACTOR (stage),
1089                               &box, CLUTTER_ALLOCATION_NONE);
1090
1091       CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
1092       CLUTTER_TIMER_STOP (_clutter_uprof_context, relayout_timer);
1093     }
1094 }
1095
1096 static gboolean
1097 _clutter_stage_get_pick_buffer_valid (ClutterStage *stage, ClutterPickMode mode)
1098 {
1099   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
1100
1101   if (stage->priv->pick_buffer_mode != mode)
1102     return FALSE;
1103
1104   return stage->priv->have_valid_pick_buffer;
1105 }
1106
1107 static void
1108 _clutter_stage_set_pick_buffer_valid (ClutterStage   *stage,
1109                                       gboolean        valid,
1110                                       ClutterPickMode mode)
1111 {
1112   g_return_if_fail (CLUTTER_IS_STAGE (stage));
1113
1114   stage->priv->have_valid_pick_buffer = !!valid;
1115   stage->priv->pick_buffer_mode = mode;
1116 }
1117
1118 static void
1119 clutter_stage_do_redraw (ClutterStage *stage)
1120 {
1121   ClutterBackend *backend = clutter_get_default_backend ();
1122   ClutterActor *actor = CLUTTER_ACTOR (stage);
1123   ClutterStagePrivate *priv = stage->priv;
1124
1125   CLUTTER_STATIC_COUNTER (redraw_counter,
1126                           "clutter_stage_do_redraw counter",
1127                           "Increments for each Stage redraw",
1128                           0 /* no application private data */);
1129   CLUTTER_STATIC_TIMER (redraw_timer,
1130                         "Master Clock", /* parent */
1131                         "Redrawing",
1132                         "The time spent redrawing everything",
1133                         0 /* no application private data */);
1134
1135   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
1136     return;
1137
1138   if (priv->impl == NULL)
1139     return;
1140
1141   CLUTTER_NOTE (PAINT, "Redraw started for stage '%s'[%p]",
1142                 _clutter_actor_get_debug_name (actor),
1143                 stage);
1144
1145   _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
1146   priv->picks_per_frame = 0;
1147
1148   _clutter_backend_ensure_context (backend, stage);
1149
1150   if (_clutter_context_get_show_fps ())
1151     {
1152       if (priv->fps_timer == NULL)
1153         priv->fps_timer = g_timer_new ();
1154     }
1155
1156   _clutter_stage_maybe_setup_viewport (stage);
1157
1158   CLUTTER_COUNTER_INC (_clutter_uprof_context, redraw_counter);
1159   CLUTTER_TIMER_START (_clutter_uprof_context, redraw_timer);
1160
1161   _clutter_stage_window_redraw (priv->impl);
1162
1163   CLUTTER_TIMER_STOP (_clutter_uprof_context, redraw_timer);
1164
1165   if (_clutter_context_get_show_fps ())
1166     {
1167       priv->timer_n_frames += 1;
1168
1169       if (g_timer_elapsed (priv->fps_timer, NULL) >= 1.0)
1170         {
1171           g_print ("*** FPS for %s: %i ***\n",
1172                    _clutter_actor_get_debug_name (actor),
1173                    priv->timer_n_frames);
1174
1175           priv->timer_n_frames = 0;
1176           g_timer_start (priv->fps_timer);
1177         }
1178     }
1179
1180   CLUTTER_NOTE (PAINT, "Redraw finished for stage '%s'[%p]",
1181                 _clutter_actor_get_debug_name (actor),
1182                 stage);
1183 }
1184
1185 /**
1186  * _clutter_stage_do_update:
1187  * @stage: A #ClutterStage
1188  *
1189  * Handles per-frame layout and repaint for the stage.
1190  *
1191  * Return value: %TRUE if the stage was updated
1192  */
1193 gboolean
1194 _clutter_stage_do_update (ClutterStage *stage)
1195 {
1196   ClutterStagePrivate *priv = stage->priv;
1197
1198   /* if the stage is being destroyed, or if the destruction already
1199    * happened and we don't have an StageWindow any more, then we
1200    * should bail out
1201    */
1202   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || priv->impl == NULL)
1203     return FALSE;
1204
1205   if (!CLUTTER_ACTOR_IS_REALIZED (stage))
1206     return FALSE;
1207
1208   /* NB: We need to ensure we have an up to date layout *before* we
1209    * check or clear the pending redraws flag since a relayout may
1210    * queue a redraw.
1211    */
1212   _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
1213
1214   if (!priv->redraw_pending)
1215     return FALSE;
1216
1217   _clutter_stage_maybe_finish_queue_redraws (stage);
1218
1219   clutter_stage_do_redraw (stage);
1220
1221   /* reset the guard, so that new redraws are possible */
1222   priv->redraw_pending = FALSE;
1223
1224 #ifdef CLUTTER_ENABLE_DEBUG
1225   if (priv->redraw_count > 0)
1226     {
1227       CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle",
1228                     priv->redraw_count);
1229
1230       priv->redraw_count = 0;
1231     }
1232 #endif /* CLUTTER_ENABLE_DEBUG */
1233
1234   return TRUE;
1235 }
1236
1237 static void
1238 clutter_stage_real_queue_relayout (ClutterActor *self)
1239 {
1240   ClutterStage *stage = CLUTTER_STAGE (self);
1241   ClutterStagePrivate *priv = stage->priv;
1242   ClutterActorClass *parent_class;
1243
1244   priv->relayout_pending = TRUE;
1245
1246   /* chain up */
1247   parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
1248   parent_class->queue_relayout (self);
1249 }
1250
1251 static void
1252 clutter_stage_real_queue_redraw (ClutterActor *actor,
1253                                  ClutterActor *leaf)
1254 {
1255   ClutterStage *stage = CLUTTER_STAGE (actor);
1256   ClutterStageWindow *stage_window;
1257   ClutterPaintVolume *redraw_clip;
1258   ClutterActorBox bounding_box;
1259   ClutterActorBox intersection_box;
1260   cairo_rectangle_int_t geom, stage_clip;
1261
1262   if (CLUTTER_ACTOR_IN_DESTRUCTION (actor))
1263     return;
1264
1265   /* If the backend can't do anything with redraw clips (e.g. it already knows
1266    * it needs to redraw everything anyway) then don't spend time transforming
1267    * any clip volume into stage coordinates... */
1268   stage_window = _clutter_stage_get_window (stage);
1269   if (stage_window == NULL)
1270     return;
1271
1272   if (_clutter_stage_window_ignoring_redraw_clips (stage_window))
1273     {
1274       _clutter_stage_window_add_redraw_clip (stage_window, NULL);
1275       return;
1276     }
1277
1278   /* Convert the clip volume into stage coordinates and then into an
1279    * axis aligned stage coordinates bounding box...
1280    */
1281   redraw_clip = _clutter_actor_get_queue_redraw_clip (leaf);
1282   if (redraw_clip == NULL)
1283     {
1284       _clutter_stage_window_add_redraw_clip (stage_window, NULL);
1285       return;
1286     }
1287
1288   _clutter_paint_volume_get_stage_paint_box (redraw_clip,
1289                                              stage,
1290                                              &bounding_box);
1291
1292   _clutter_stage_window_get_geometry (stage_window, &geom);
1293
1294   intersection_box.x1 = MAX (bounding_box.x1, 0);
1295   intersection_box.y1 = MAX (bounding_box.y1, 0);
1296   intersection_box.x2 = MIN (bounding_box.x2, geom.width);
1297   intersection_box.y2 = MIN (bounding_box.y2, geom.height);
1298
1299   /* There is no need to track degenerate/empty redraw clips */
1300   if (intersection_box.x2 <= intersection_box.x1 ||
1301       intersection_box.y2 <= intersection_box.y1)
1302     return;
1303
1304   /* when converting to integer coordinates make sure we round the edges of the
1305    * clip rectangle outwards... */
1306   stage_clip.x = intersection_box.x1;
1307   stage_clip.y = intersection_box.y1;
1308   stage_clip.width = intersection_box.x2 - stage_clip.x;
1309   stage_clip.height = intersection_box.y2 - stage_clip.y;
1310
1311   _clutter_stage_window_add_redraw_clip (stage_window, &stage_clip);
1312 }
1313
1314 gboolean
1315 _clutter_stage_has_full_redraw_queued (ClutterStage *stage)
1316 {
1317   ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
1318
1319   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || stage_window == NULL)
1320     return FALSE;
1321
1322   if (stage->priv->redraw_pending &&
1323       !_clutter_stage_window_has_redraw_clips (stage_window))
1324     return TRUE;
1325   else
1326     return FALSE;
1327 }
1328
1329 /**
1330  * clutter_stage_get_redraw_clip_bounds:
1331  * @stage: A #ClutterStage
1332  * @clip: (out caller-allocates): Return location for the clip bounds
1333  *
1334  * Gets the bounds of the current redraw for @stage in stage pixel
1335  * coordinates. E.g., if only a single actor has queued a redraw then
1336  * Clutter may redraw the stage with a clip so that it doesn't have to
1337  * paint every pixel in the stage. This function would then return the
1338  * bounds of that clip. An application can use this information to
1339  * avoid some extra work if it knows that some regions of the stage
1340  * aren't going to be painted. This should only be called while the
1341  * stage is being painted. If there is no current redraw clip then
1342  * this function will set @clip to the full extents of the stage.
1343  *
1344  * Since: 1.8
1345  */
1346 void
1347 clutter_stage_get_redraw_clip_bounds (ClutterStage          *stage,
1348                                       cairo_rectangle_int_t *clip)
1349 {
1350   ClutterStagePrivate *priv;
1351
1352   g_return_if_fail (CLUTTER_IS_STAGE (stage));
1353   g_return_if_fail (clip != NULL);
1354
1355   priv = stage->priv;
1356
1357   if (!_clutter_stage_window_get_redraw_clip_bounds (priv->impl, clip))
1358     {
1359       /* Set clip to the full extents of the stage */
1360       _clutter_stage_window_get_geometry (priv->impl, clip);
1361     }
1362 }
1363
1364 static void
1365 read_pixels_to_file (char *filename_stem,
1366                      int   x,
1367                      int   y,
1368                      int   width,
1369                      int   height)
1370 {
1371   GLubyte *data;
1372   cairo_surface_t *surface;
1373   static int read_count = 0;
1374   char *filename = g_strdup_printf ("%s-%05d.png",
1375                                     filename_stem,
1376                                     read_count);
1377
1378   data = g_malloc (4 * width * height);
1379   cogl_read_pixels (x, y, width, height,
1380                     COGL_READ_PIXELS_COLOR_BUFFER,
1381                     CLUTTER_CAIRO_FORMAT_ARGB32,
1382                     data);
1383
1384   surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
1385                                                  width, height,
1386                                                  width * 4);
1387
1388   cairo_surface_write_to_png (surface, filename);
1389   cairo_surface_destroy (surface);
1390
1391   g_free (data);
1392   g_free (filename);
1393
1394   read_count++;
1395 }
1396
1397 ClutterActor *
1398 _clutter_stage_do_pick (ClutterStage   *stage,
1399                         gint            x,
1400                         gint            y,
1401                         ClutterPickMode mode)
1402 {
1403   ClutterStagePrivate *priv;
1404   ClutterMainContext *context;
1405   guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
1406   CoglColor stage_pick_id;
1407   gboolean dither_enabled_save;
1408   CoglFramebuffer *fb;
1409   ClutterActor *actor;
1410   gboolean is_clipped;
1411   CLUTTER_STATIC_COUNTER (do_pick_counter,
1412                           "_clutter_stage_do_pick counter",
1413                           "Increments for each full pick run",
1414                           0 /* no application private data */);
1415   CLUTTER_STATIC_TIMER (pick_timer,
1416                         "Mainloop", /* parent */
1417                         "Picking",
1418                         "The time spent picking",
1419                         0 /* no application private data */);
1420   CLUTTER_STATIC_TIMER (pick_clear,
1421                         "Picking", /* parent */
1422                         "Stage clear (pick)",
1423                         "The time spent clearing stage for picking",
1424                         0 /* no application private data */);
1425   CLUTTER_STATIC_TIMER (pick_paint,
1426                         "Picking", /* parent */
1427                         "Painting actors (pick mode)",
1428                         "The time spent painting actors in pick mode",
1429                         0 /* no application private data */);
1430   CLUTTER_STATIC_TIMER (pick_read,
1431                         "Picking", /* parent */
1432                         "Read Pixels",
1433                         "The time spent issuing a read pixels",
1434                         0 /* no application private data */);
1435
1436   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
1437
1438   priv = stage->priv;
1439
1440   if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_NOP_PICKING))
1441     return CLUTTER_ACTOR (stage);
1442
1443 #ifdef CLUTTER_ENABLE_PROFILE
1444   if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
1445     _clutter_profile_resume ();
1446 #endif /* CLUTTER_ENABLE_PROFILE */
1447
1448   CLUTTER_COUNTER_INC (_clutter_uprof_context, do_pick_counter);
1449   CLUTTER_TIMER_START (_clutter_uprof_context, pick_timer);
1450
1451   context = _clutter_context_get_default ();
1452   clutter_stage_ensure_current (stage);
1453
1454   /* It's possible that we currently have a static scene and have renderered a
1455    * full, unclipped pick buffer. If so we can simply continue to read from
1456    * this cached buffer until the scene next changes. */
1457   if (_clutter_stage_get_pick_buffer_valid (stage, mode))
1458     {
1459       CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
1460       cogl_read_pixels (x, y, 1, 1,
1461                         COGL_READ_PIXELS_COLOR_BUFFER,
1462                         COGL_PIXEL_FORMAT_RGBA_8888_PRE,
1463                         pixel);
1464       CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
1465
1466       CLUTTER_NOTE (PICK, "Reusing pick buffer from previous render to fetch "
1467                     "actor at %i,%i", x, y);
1468
1469       goto check_pixel;
1470     }
1471
1472   priv->picks_per_frame++;
1473
1474   _clutter_backend_ensure_context (context->backend, stage);
1475
1476   /* needed for when a context switch happens */
1477   _clutter_stage_maybe_setup_viewport (stage);
1478
1479   /* If we are seeing multiple picks per frame that means the scene is static
1480    * so we promote to doing a non-scissored pick render so that all subsequent
1481    * picks for the same static scene won't require additional renders */
1482   if (priv->picks_per_frame < 2)
1483     {
1484       if (G_LIKELY (!(clutter_pick_debug_flags &
1485                       CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
1486         cogl_clip_push_window_rectangle (x, y, 1, 1);
1487       is_clipped = TRUE;
1488     }
1489   else
1490     is_clipped = FALSE;
1491
1492   CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
1493                 is_clipped ? "clippped" : "full", x, y);
1494
1495   cogl_disable_fog ();
1496   cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
1497   CLUTTER_TIMER_START (_clutter_uprof_context, pick_clear);
1498   cogl_clear (&stage_pick_id,
1499               COGL_BUFFER_BIT_COLOR |
1500               COGL_BUFFER_BIT_DEPTH);
1501   CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_clear);
1502
1503   /* Disable dithering (if any) when doing the painting in pick mode */
1504   fb = cogl_get_draw_framebuffer ();
1505   dither_enabled_save = cogl_framebuffer_get_dither_enabled (fb);
1506   cogl_framebuffer_set_dither_enabled (fb, FALSE);
1507
1508   /* Render the entire scence in pick mode - just single colored silhouette's
1509    * are drawn offscreen (as we never swap buffers)
1510   */
1511   CLUTTER_TIMER_START (_clutter_uprof_context, pick_paint);
1512   context->pick_mode = mode;
1513   _clutter_stage_do_paint (stage, NULL);
1514   context->pick_mode = CLUTTER_PICK_NONE;
1515   CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
1516
1517   if (is_clipped)
1518     {
1519       if (G_LIKELY (!(clutter_pick_debug_flags &
1520                       CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
1521         cogl_clip_pop ();
1522
1523       _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
1524     }
1525   else
1526     _clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
1527
1528   /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
1529      even though we don't care about the alpha component because under
1530      GLES this is the only format that is guaranteed to work so Cogl
1531      will end up having to do a conversion if any other format is
1532      used. The format is requested as pre-multiplied because Cogl
1533      assumes that all pixels in the framebuffer are premultiplied so
1534      it avoids a conversion. */
1535   CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
1536   cogl_read_pixels (x, y, 1, 1,
1537                     COGL_READ_PIXELS_COLOR_BUFFER,
1538                     COGL_PIXEL_FORMAT_RGBA_8888_PRE,
1539                     pixel);
1540   CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_read);
1541
1542   if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
1543     {
1544       char *file_name =
1545         g_strconcat ("pick-buffer-",
1546                      _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
1547                      NULL);
1548
1549       read_pixels_to_file (file_name, 0, 0,
1550                            clutter_actor_get_width (CLUTTER_ACTOR (stage)),
1551                            clutter_actor_get_height (CLUTTER_ACTOR (stage)));
1552
1553       g_free (file_name);
1554     }
1555
1556   /* Restore whether GL_DITHER was enabled */
1557   cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save);
1558
1559 check_pixel:
1560   if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
1561     {
1562       actor = CLUTTER_ACTOR (stage);
1563     }
1564   else
1565     {
1566       guint32 id_ = _clutter_pixel_to_id (pixel);
1567
1568       actor = _clutter_get_actor_by_id (stage, id_);
1569     }
1570
1571   CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_timer);
1572
1573 #ifdef CLUTTER_ENABLE_PROFILE
1574   if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY)
1575     _clutter_profile_suspend ();
1576 #endif
1577
1578   return actor;
1579 }
1580
1581
1582
1583 static gboolean
1584 clutter_stage_real_delete_event (ClutterStage *stage,
1585                                  ClutterEvent *event)
1586 {
1587   if (stage_is_default (stage))
1588     clutter_main_quit ();
1589   else
1590     clutter_actor_destroy (CLUTTER_ACTOR (stage));
1591
1592   return TRUE;
1593 }
1594
1595 static void
1596 clutter_stage_real_apply_transform (ClutterActor *stage,
1597                                     CoglMatrix   *matrix)
1598 {
1599   ClutterStagePrivate *priv = CLUTTER_STAGE (stage)->priv;
1600
1601   /* FIXME: we probably shouldn't be explicitly reseting the matrix
1602    * here... */
1603   cogl_matrix_init_identity (matrix);
1604   cogl_matrix_multiply (matrix, matrix, &priv->view);
1605 }
1606
1607 static void
1608 clutter_stage_constructed (GObject *gobject)
1609 {
1610   ClutterStage *self = CLUTTER_STAGE (gobject);
1611   ClutterStageManager *stage_manager;
1612
1613   stage_manager = clutter_stage_manager_get_default ();
1614
1615   /* this will take care to sinking the floating reference */
1616   _clutter_stage_manager_add_stage (stage_manager, self);
1617
1618   /* if this stage has been created on a backend that does not
1619    * support multiple stages then it becomes the default stage
1620    * as well; any other attempt at creating a ClutterStage will
1621    * fail.
1622    */
1623   if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
1624     {
1625       if (G_UNLIKELY (clutter_stage_manager_get_default_stage (stage_manager) != NULL))
1626         {
1627           g_error ("Unable to create another stage: the backend of "
1628                    "type '%s' does not support multiple stages. Use "
1629                    "clutter_stage_manager_get_default_stage() instead "
1630                    "to access the stage singleton.",
1631                    G_OBJECT_TYPE_NAME (clutter_get_default_backend ()));
1632         }
1633
1634       _clutter_stage_manager_set_default_stage (stage_manager, self);
1635     }
1636
1637   G_OBJECT_CLASS (clutter_stage_parent_class)->constructed (gobject);
1638 }
1639
1640 static void
1641 clutter_stage_set_property (GObject      *object,
1642                             guint         prop_id,
1643                             const GValue *value,
1644                             GParamSpec   *pspec)
1645 {
1646   ClutterStage *stage = CLUTTER_STAGE (object);
1647
1648   switch (prop_id)
1649     {
1650     case PROP_COLOR:
1651       clutter_actor_set_background_color (CLUTTER_ACTOR (stage),
1652                                           clutter_value_get_color (value));
1653       break;
1654
1655     case PROP_OFFSCREEN:
1656       if (g_value_get_boolean (value))
1657         g_warning ("Offscreen stages are currently not supported\n");
1658       break;
1659
1660     case PROP_CURSOR_VISIBLE:
1661       if (g_value_get_boolean (value))
1662         clutter_stage_show_cursor (stage);
1663       else
1664         clutter_stage_hide_cursor (stage);
1665       break;
1666
1667     case PROP_PERSPECTIVE:
1668       clutter_stage_set_perspective (stage, g_value_get_boxed (value));
1669       break;
1670
1671     case PROP_TITLE:
1672       clutter_stage_set_title (stage, g_value_get_string (value));
1673       break;
1674
1675     case PROP_USER_RESIZABLE:
1676       clutter_stage_set_user_resizable (stage, g_value_get_boolean (value));
1677       break;
1678
1679     case PROP_USE_FOG:
1680       clutter_stage_set_use_fog (stage, g_value_get_boolean (value));
1681       break;
1682
1683     case PROP_FOG:
1684       clutter_stage_set_fog (stage, g_value_get_boxed (value));
1685       break;
1686
1687     case PROP_USE_ALPHA:
1688       clutter_stage_set_use_alpha (stage, g_value_get_boolean (value));
1689       break;
1690
1691     case PROP_KEY_FOCUS:
1692       clutter_stage_set_key_focus (stage, g_value_get_object (value));
1693       break;
1694
1695     case PROP_NO_CLEAR_HINT:
1696       clutter_stage_set_no_clear_hint (stage, g_value_get_boolean (value));
1697       break;
1698
1699     case PROP_ACCEPT_FOCUS:
1700       clutter_stage_set_accept_focus (stage, g_value_get_boolean (value));
1701       break;
1702
1703     default:
1704       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1705       break;
1706   }
1707 }
1708
1709 static void
1710 clutter_stage_get_property (GObject    *gobject,
1711                             guint       prop_id,
1712                             GValue     *value,
1713                             GParamSpec *pspec)
1714 {
1715   ClutterStagePrivate *priv = CLUTTER_STAGE (gobject)->priv;
1716
1717   switch (prop_id)
1718     {
1719     case PROP_COLOR:
1720       {
1721         ClutterColor bg_color;
1722
1723         clutter_actor_get_background_color (CLUTTER_ACTOR (gobject),
1724                                             &bg_color);
1725         clutter_value_set_color (value, &bg_color);
1726       }
1727       break;
1728
1729     case PROP_OFFSCREEN:
1730       g_value_set_boolean (value, FALSE);
1731       break;
1732
1733     case PROP_FULLSCREEN_SET:
1734       g_value_set_boolean (value, priv->is_fullscreen);
1735       break;
1736
1737     case PROP_CURSOR_VISIBLE:
1738       g_value_set_boolean (value, priv->is_cursor_visible);
1739       break;
1740
1741     case PROP_PERSPECTIVE:
1742       g_value_set_boxed (value, &priv->perspective);
1743       break;
1744
1745     case PROP_TITLE:
1746       g_value_set_string (value, priv->title);
1747       break;
1748
1749     case PROP_USER_RESIZABLE:
1750       g_value_set_boolean (value, priv->is_user_resizable);
1751       break;
1752
1753     case PROP_USE_FOG:
1754       g_value_set_boolean (value, priv->use_fog);
1755       break;
1756
1757     case PROP_FOG:
1758       g_value_set_boxed (value, &priv->fog);
1759       break;
1760
1761     case PROP_USE_ALPHA:
1762       g_value_set_boolean (value, priv->use_alpha);
1763       break;
1764
1765     case PROP_KEY_FOCUS:
1766       g_value_set_object (value, priv->key_focused_actor);
1767       break;
1768
1769     case PROP_NO_CLEAR_HINT:
1770       {
1771         gboolean hint =
1772           (priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0;
1773
1774         g_value_set_boolean (value, hint);
1775       }
1776       break;
1777
1778     case PROP_ACCEPT_FOCUS:
1779       g_value_set_boolean (value, priv->accept_focus);
1780       break;
1781
1782     default:
1783       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
1784       break;
1785     }
1786 }
1787
1788 static void
1789 clutter_stage_dispose (GObject *object)
1790 {
1791   ClutterStage        *stage = CLUTTER_STAGE (object);
1792   ClutterStagePrivate *priv = stage->priv;
1793   ClutterStageManager *stage_manager;
1794
1795   clutter_actor_hide (CLUTTER_ACTOR (object));
1796
1797   /* remove_stage() will unref() the stage instance, so we need to
1798    * add a reference here to keep it temporarily alive
1799    */
1800   g_object_ref (object);
1801   stage_manager = clutter_stage_manager_get_default ();
1802   _clutter_stage_manager_remove_stage (stage_manager, stage);
1803
1804   _clutter_clear_events_queue_for_stage (stage);
1805
1806   if (priv->impl != NULL)
1807     {
1808       CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation");
1809
1810       if (CLUTTER_ACTOR_IS_REALIZED (object))
1811         _clutter_stage_window_unrealize (priv->impl);
1812
1813       g_object_unref (priv->impl);
1814       priv->impl = NULL;
1815     }
1816
1817   clutter_actor_remove_all_children (CLUTTER_ACTOR (object));
1818
1819   G_OBJECT_CLASS (clutter_stage_parent_class)->dispose (object);
1820 }
1821
1822 static void
1823 clutter_stage_finalize (GObject *object)
1824 {
1825   ClutterStage *stage = CLUTTER_STAGE (object);
1826   ClutterStagePrivate *priv = stage->priv;
1827
1828   g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL);
1829   g_queue_free (priv->event_queue);
1830
1831   g_free (priv->title);
1832
1833   g_array_free (priv->paint_volume_stack, TRUE);
1834
1835   g_hash_table_destroy (priv->devices);
1836
1837   _clutter_id_pool_free (priv->pick_id_pool);
1838
1839   if (priv->fps_timer != NULL)
1840     g_timer_destroy (priv->fps_timer);
1841
1842   G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
1843 }
1844
1845 static void
1846 clutter_stage_class_init (ClutterStageClass *klass)
1847 {
1848   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1849   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
1850   GParamSpec *pspec;
1851
1852   gobject_class->constructed = clutter_stage_constructed;
1853   gobject_class->set_property = clutter_stage_set_property;
1854   gobject_class->get_property = clutter_stage_get_property;
1855   gobject_class->dispose = clutter_stage_dispose;
1856   gobject_class->finalize = clutter_stage_finalize;
1857
1858   actor_class->allocate = clutter_stage_allocate;
1859   actor_class->get_preferred_width = clutter_stage_get_preferred_width;
1860   actor_class->get_preferred_height = clutter_stage_get_preferred_height;
1861   actor_class->paint = clutter_stage_paint;
1862   actor_class->pick = clutter_stage_pick;
1863   actor_class->get_paint_volume = clutter_stage_get_paint_volume;
1864   actor_class->realize = clutter_stage_realize;
1865   actor_class->unrealize = clutter_stage_unrealize;
1866   actor_class->show = clutter_stage_show;
1867   actor_class->show_all = clutter_stage_show_all;
1868   actor_class->hide = clutter_stage_hide;
1869   actor_class->hide_all = clutter_stage_hide_all;
1870   actor_class->queue_relayout = clutter_stage_real_queue_relayout;
1871   actor_class->queue_redraw = clutter_stage_real_queue_redraw;
1872   actor_class->apply_transform = clutter_stage_real_apply_transform;
1873
1874   /**
1875    * ClutterStage:fullscreen:
1876    *
1877    * Whether the stage should be fullscreen or not.
1878    *
1879    * This property is set by calling clutter_stage_set_fullscreen()
1880    * but since the actual implementation is delegated to the backend
1881    * you should connect to the notify::fullscreen-set signal in order
1882    * to get notification if the fullscreen state has been successfully
1883    * achieved.
1884    *
1885    * Since: 1.0
1886    */
1887   pspec = g_param_spec_boolean ("fullscreen-set",
1888                                 P_("Fullscreen Set"),
1889                                 P_("Whether the main stage is fullscreen"),
1890                                 FALSE,
1891                                 CLUTTER_PARAM_READABLE);
1892   g_object_class_install_property (gobject_class,
1893                                    PROP_FULLSCREEN_SET,
1894                                    pspec);
1895   /**
1896    * ClutterStage:offscreen:
1897    *
1898    * Whether the stage should be rendered in an offscreen buffer.
1899    *
1900    * Deprecated: 1.10: This property does not do anything.
1901    */
1902   pspec = g_param_spec_boolean ("offscreen",
1903                                 P_("Offscreen"),
1904                                 P_("Whether the main stage should be rendered offscreen"),
1905                                 FALSE,
1906                                 CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
1907   g_object_class_install_property (gobject_class,
1908                                    PROP_OFFSCREEN,
1909                                    pspec);
1910   /**
1911    * ClutterStage:cursor-visible:
1912    *
1913    * Whether the mouse pointer should be visible
1914    */
1915   pspec = g_param_spec_boolean ("cursor-visible",
1916                                 P_("Cursor Visible"),
1917                                 P_("Whether the mouse pointer is visible on the main stage"),
1918                                 TRUE,
1919                                 CLUTTER_PARAM_READWRITE);
1920   g_object_class_install_property (gobject_class,
1921                                    PROP_CURSOR_VISIBLE,
1922                                    pspec);
1923   /**
1924    * ClutterStage:user-resizable:
1925    *
1926    * Whether the stage is resizable via user interaction.
1927    *
1928    * Since: 0.4
1929    */
1930   pspec = g_param_spec_boolean ("user-resizable",
1931                                 P_("User Resizable"),
1932                                 P_("Whether the stage is able to be resized via user interaction"),
1933                                 FALSE,
1934                                 CLUTTER_PARAM_READWRITE);
1935   g_object_class_install_property (gobject_class,
1936                                    PROP_USER_RESIZABLE,
1937                                    pspec);
1938   /**
1939    * ClutterStage:color:
1940    *
1941    * The background color of the main stage.
1942    *
1943    * Deprecated: 1.10: Use the #ClutterActor:background-color property of
1944    *   #ClutterActor instead.
1945    */
1946   pspec = clutter_param_spec_color ("color",
1947                                     P_("Color"),
1948                                     P_("The color of the stage"),
1949                                     &default_stage_color,
1950                                     CLUTTER_PARAM_READWRITE |
1951                                     G_PARAM_DEPRECATED);
1952   g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
1953
1954   /**
1955    * ClutterStage:perspective:
1956    *
1957    * The parameters used for the perspective projection from 3D
1958    * coordinates to 2D
1959    *
1960    * Since: 0.8.2
1961    */
1962   pspec = g_param_spec_boxed ("perspective",
1963                               P_("Perspective"),
1964                               P_("Perspective projection parameters"),
1965                               CLUTTER_TYPE_PERSPECTIVE,
1966                               CLUTTER_PARAM_READWRITE);
1967   g_object_class_install_property (gobject_class,
1968                                    PROP_PERSPECTIVE,
1969                                    pspec);
1970
1971   /**
1972    * ClutterStage:title:
1973    *
1974    * The stage's title - usually displayed in stage windows title decorations.
1975    *
1976    * Since: 0.4
1977    */
1978   pspec = g_param_spec_string ("title",
1979                                P_("Title"),
1980                                P_("Stage Title"),
1981                                NULL,
1982                                CLUTTER_PARAM_READWRITE);
1983   g_object_class_install_property (gobject_class, PROP_TITLE, pspec);
1984
1985   /**
1986    * ClutterStage:use-fog:
1987    *
1988    * Whether the stage should use a linear GL "fog" in creating the
1989    * depth-cueing effect, to enhance the perception of depth by fading
1990    * actors farther from the viewpoint.
1991    *
1992    * Since: 0.6
1993    *
1994    * Deprecated: 1.10: This property does not do anything.
1995    */
1996   pspec = g_param_spec_boolean ("use-fog",
1997                                 P_("Use Fog"),
1998                                 P_("Whether to enable depth cueing"),
1999                                 FALSE,
2000                                 CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
2001   g_object_class_install_property (gobject_class, PROP_USE_FOG, pspec);
2002
2003   /**
2004    * ClutterStage:fog:
2005    *
2006    * The settings for the GL "fog", used only if #ClutterStage:use-fog
2007    * is set to %TRUE
2008    *
2009    * Since: 1.0
2010    *
2011    * Deprecated: 1.10: This property does not do anything.
2012    */
2013   pspec = g_param_spec_boxed ("fog",
2014                               P_("Fog"),
2015                               P_("Settings for the depth cueing"),
2016                               CLUTTER_TYPE_FOG,
2017                               CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
2018   g_object_class_install_property (gobject_class, PROP_FOG, pspec);
2019
2020   /**
2021    * ClutterStage:use-alpha:
2022    *
2023    * Whether the #ClutterStage should honour the alpha component of the
2024    * #ClutterStage:color property when painting. If Clutter is run under
2025    * a compositing manager this will result in the stage being blended
2026    * with the underlying window(s)
2027    *
2028    * Since: 1.2
2029    */
2030   pspec = g_param_spec_boolean ("use-alpha",
2031                                 P_("Use Alpha"),
2032                                 P_("Whether to honour the alpha component of the stage color"),
2033                                 FALSE,
2034                                 CLUTTER_PARAM_READWRITE);
2035   g_object_class_install_property (gobject_class, PROP_USE_ALPHA, pspec);
2036
2037   /**
2038    * ClutterStage:key-focus:
2039    *
2040    * The #ClutterActor that will receive key events from the underlying
2041    * windowing system.
2042    *
2043    * If %NULL, the #ClutterStage will receive the events.
2044    *
2045    * Since: 1.2
2046    */
2047   pspec = g_param_spec_object ("key-focus",
2048                                P_("Key Focus"),
2049                                P_("The currently key focused actor"),
2050                                CLUTTER_TYPE_ACTOR,
2051                                CLUTTER_PARAM_READWRITE);
2052   g_object_class_install_property (gobject_class, PROP_KEY_FOCUS, pspec);
2053
2054   /**
2055    * ClutterStage:no-clear-hint:
2056    *
2057    * Whether or not the #ClutterStage should clear its contents
2058    * before each paint cycle.
2059    *
2060    * See clutter_stage_set_no_clear_hint() for further information.
2061    *
2062    * Since: 1.4
2063    */
2064   pspec = g_param_spec_boolean ("no-clear-hint",
2065                                 P_("No Clear Hint"),
2066                                 P_("Whether the stage should clear its contents"),
2067                                 FALSE,
2068                                 CLUTTER_PARAM_READWRITE);
2069   g_object_class_install_property (gobject_class, PROP_NO_CLEAR_HINT, pspec);
2070
2071   /**
2072    * ClutterStage:accept-focus:
2073    *
2074    * Whether the #ClutterStage should accept key focus when shown.
2075    *
2076    * Since: 1.6
2077    */
2078   pspec = g_param_spec_boolean ("accept-focus",
2079                                 P_("Accept Focus"),
2080                                 P_("Whether the stage should accept focus on show"),
2081                                 TRUE,
2082                                 CLUTTER_PARAM_READWRITE);
2083   g_object_class_install_property (gobject_class, PROP_ACCEPT_FOCUS, pspec);
2084
2085   /**
2086    * ClutterStage::fullscreen
2087    * @stage: the stage which was fullscreened
2088    *
2089    * The ::fullscreen signal is emitted when the stage is made fullscreen.
2090    *
2091    * Since: 0.6
2092    */
2093   stage_signals[FULLSCREEN] =
2094     g_signal_new (I_("fullscreen"),
2095                   G_TYPE_FROM_CLASS (gobject_class),
2096                   G_SIGNAL_RUN_FIRST,
2097                   G_STRUCT_OFFSET (ClutterStageClass, fullscreen),
2098                   NULL, NULL,
2099                   _clutter_marshal_VOID__VOID,
2100                   G_TYPE_NONE, 0);
2101   /**
2102    * ClutterStage::unfullscreen
2103    * @stage: the stage which has left a fullscreen state.
2104    *
2105    * The ::unfullscreen signal is emitted when the stage leaves a fullscreen
2106    * state.
2107    *
2108    * Since: 0.6
2109    */
2110   stage_signals[UNFULLSCREEN] =
2111     g_signal_new (I_("unfullscreen"),
2112                   G_TYPE_FROM_CLASS (gobject_class),
2113                   G_SIGNAL_RUN_LAST,
2114                   G_STRUCT_OFFSET (ClutterStageClass, unfullscreen),
2115                   NULL, NULL,
2116                   _clutter_marshal_VOID__VOID,
2117                   G_TYPE_NONE, 0);
2118   /**
2119    * ClutterStage::activate
2120    * @stage: the stage which was activated
2121    *
2122    * The ::activate signal is emitted when the stage receives key focus
2123    * from the underlying window system.
2124    *
2125    * Since: 0.6
2126    */
2127   stage_signals[ACTIVATE] =
2128     g_signal_new (I_("activate"),
2129                   G_TYPE_FROM_CLASS (gobject_class),
2130                   G_SIGNAL_RUN_LAST,
2131                   G_STRUCT_OFFSET (ClutterStageClass, activate),
2132                   NULL, NULL,
2133                   _clutter_marshal_VOID__VOID,
2134                   G_TYPE_NONE, 0);
2135   /**
2136    * ClutterStage::deactivate
2137    * @stage: the stage which was deactivated
2138    *
2139    * The ::activate signal is emitted when the stage loses key focus
2140    * from the underlying window system.
2141    *
2142    * Since: 0.6
2143    */
2144   stage_signals[DEACTIVATE] =
2145     g_signal_new (I_("deactivate"),
2146                   G_TYPE_FROM_CLASS (gobject_class),
2147                   G_SIGNAL_RUN_LAST,
2148                   G_STRUCT_OFFSET (ClutterStageClass, deactivate),
2149                   NULL, NULL,
2150                   _clutter_marshal_VOID__VOID,
2151                   G_TYPE_NONE, 0);
2152
2153   /**
2154    * ClutterStage::delete-event:
2155    * @stage: the stage that received the event
2156    * @event: a #ClutterEvent of type %CLUTTER_DELETE
2157    *
2158    * The ::delete-event signal is emitted when the user closes a
2159    * #ClutterStage window using the window controls.
2160    *
2161    * Clutter by default will call clutter_main_quit() if @stage is
2162    * the default stage, and clutter_actor_destroy() for any other
2163    * stage.
2164    *
2165    * It is possible to override the default behaviour by connecting
2166    * a new handler and returning %TRUE there.
2167    *
2168    * <note>This signal is emitted only on Clutter backends that
2169    * embed #ClutterStage in native windows. It is not emitted for
2170    * backends that use a static frame buffer.</note>
2171    *
2172    * Since: 1.2
2173    */
2174   stage_signals[DELETE_EVENT] =
2175     g_signal_new (I_("delete-event"),
2176                   G_TYPE_FROM_CLASS (gobject_class),
2177                   G_SIGNAL_RUN_LAST,
2178                   G_STRUCT_OFFSET (ClutterStageClass, delete_event),
2179                   _clutter_boolean_handled_accumulator, NULL,
2180                   _clutter_marshal_BOOLEAN__BOXED,
2181                   G_TYPE_BOOLEAN, 1,
2182                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
2183
2184   klass->fullscreen = clutter_stage_real_fullscreen;
2185   klass->activate = clutter_stage_real_activate;
2186   klass->deactivate = clutter_stage_real_deactivate;
2187   klass->delete_event = clutter_stage_real_delete_event;
2188
2189   g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
2190 }
2191
2192 static void
2193 clutter_stage_notify_min_size (ClutterStage *self)
2194 {
2195   self->priv->min_size_changed = TRUE;
2196 }
2197
2198 static void
2199 clutter_stage_init (ClutterStage *self)
2200 {
2201   cairo_rectangle_int_t geom = { 0, };
2202   ClutterStagePrivate *priv;
2203   ClutterStageWindow *impl;
2204   ClutterBackend *backend;
2205   GError *error;
2206
2207   /* a stage is a top-level object */
2208   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL);
2209
2210   self->priv = priv = CLUTTER_STAGE_GET_PRIVATE (self);
2211
2212   CLUTTER_NOTE (BACKEND, "Creating stage from the default backend");
2213   backend = clutter_get_default_backend ();
2214
2215   error = NULL;
2216   impl = _clutter_backend_create_stage (backend, self, &error);
2217
2218   if (G_LIKELY (impl != NULL))
2219     {
2220       _clutter_stage_set_window (self, impl);
2221       _clutter_stage_window_get_geometry (priv->impl, &geom);
2222     }
2223   else
2224     {
2225       if (error != NULL)
2226         {
2227           g_critical ("Unable to create a new stage implementation: %s",
2228                       error->message);
2229           g_error_free (error);
2230         }
2231       else
2232         g_critical ("Unable to create a new stage implementation.");
2233     }
2234
2235   priv->event_queue = g_queue_new ();
2236
2237   priv->is_fullscreen = FALSE;
2238   priv->is_user_resizable = FALSE;
2239   priv->is_cursor_visible = TRUE;
2240   priv->use_fog = FALSE;
2241   priv->throttle_motion_events = TRUE;
2242   priv->min_size_changed = FALSE;
2243
2244   /* XXX - we need to keep the invariant that calling
2245    * clutter_set_motion_event_enabled() before the stage creation
2246    * will cause motion event delivery to be disabled on any newly
2247    * created stage. this can go away when we break API and remove
2248    * deprecated functions.
2249    */
2250   priv->motion_events_enabled = _clutter_context_get_motion_events_enabled ();
2251
2252   clutter_actor_set_background_color (CLUTTER_ACTOR (self),
2253                                       &default_stage_color);
2254
2255   priv->perspective.fovy   = 60.0; /* 60 Degrees */
2256   priv->perspective.aspect = (float) geom.width / (float) geom.height;
2257   priv->perspective.z_near = 0.1;
2258   priv->perspective.z_far  = 100.0;
2259
2260   cogl_matrix_init_identity (&priv->projection);
2261   cogl_matrix_perspective (&priv->projection,
2262                            priv->perspective.fovy,
2263                            priv->perspective.aspect,
2264                            priv->perspective.z_near,
2265                            priv->perspective.z_far);
2266   cogl_matrix_get_inverse (&priv->projection,
2267                            &priv->inverse_projection);
2268   cogl_matrix_init_identity (&priv->view);
2269   cogl_matrix_view_2d_in_perspective (&priv->view,
2270                                       priv->perspective.fovy,
2271                                       priv->perspective.aspect,
2272                                       priv->perspective.z_near,
2273                                       50, /* distance to 2d plane */
2274                                       geom.width,
2275                                       geom.height);
2276
2277
2278   /* FIXME - remove for 2.0 */
2279   priv->fog.z_near = 1.0;
2280   priv->fog.z_far  = 2.0;
2281
2282   priv->relayout_pending = TRUE;
2283
2284   clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
2285   clutter_stage_set_title (self, g_get_prgname ());
2286   clutter_stage_set_key_focus (self, NULL);
2287
2288   g_signal_connect (self, "notify::min-width",
2289                     G_CALLBACK (clutter_stage_notify_min_size), NULL);
2290   g_signal_connect (self, "notify::min-height",
2291                     G_CALLBACK (clutter_stage_notify_min_size), NULL);
2292
2293   _clutter_stage_set_viewport (self, 0, 0, geom.width, geom.height);
2294
2295   _clutter_stage_set_pick_buffer_valid (self, FALSE, CLUTTER_PICK_ALL);
2296   priv->picks_per_frame = 0;
2297
2298   priv->paint_volume_stack =
2299     g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
2300
2301   priv->devices = g_hash_table_new (NULL, NULL);
2302
2303   priv->pick_id_pool = _clutter_id_pool_new (256);
2304 }
2305
2306 /**
2307  * clutter_stage_get_default:
2308  *
2309  * Retrieves a #ClutterStage singleton.
2310  *
2311  * This function is not as useful as it sounds, and will most likely
2312  * by deprecated in the future. Application code should only create
2313  * a #ClutterStage instance using clutter_stage_new(), and manage the
2314  * lifetime of the stage manually.
2315  *
2316  * The default stage singleton has a platform-specific behaviour: on
2317  * platforms without the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag
2318  * set, the first #ClutterStage instance will also be set to be the
2319  * default stage instance, and this function will always return a
2320  * pointer to it.
2321  *
2322  * On platforms with the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag
2323  * set, the default stage will be created by the first call to this
2324  * function, and every following call will return the same pointer to
2325  * it.
2326  *
2327  * Return value: (transfer none) (type Clutter.Stage): the main
2328  *   #ClutterStage. You should never destroy or unref the returned
2329  *   actor.
2330  *
2331  * Deprecated: 1.10: Use clutter_stage_new() instead.
2332  */
2333 ClutterActor *
2334 clutter_stage_get_default (void)
2335 {
2336   ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
2337   ClutterStage *stage;
2338
2339   stage = clutter_stage_manager_get_default_stage (stage_manager);
2340   if (G_UNLIKELY (stage == NULL))
2341     {
2342       /* This will take care of automatically adding the stage to the
2343        * stage manager and setting it as the default. Its floating
2344        * reference will be claimed by the stage manager.
2345        */
2346       stage = g_object_new (CLUTTER_TYPE_STAGE, NULL);
2347       _clutter_stage_manager_set_default_stage (stage_manager, stage);
2348
2349       /* the default stage is realized by default */
2350       clutter_actor_realize (CLUTTER_ACTOR (stage));
2351     }
2352
2353   return CLUTTER_ACTOR (stage);
2354 }
2355
2356 /**
2357  * clutter_stage_set_color:
2358  * @stage: A #ClutterStage
2359  * @color: A #ClutterColor
2360  *
2361  * Sets the stage color.
2362  *
2363  * Deprecated: 1.10: Use clutter_actor_set_background_color() instead.
2364  */
2365 void
2366 clutter_stage_set_color (ClutterStage       *stage,
2367                          const ClutterColor *color)
2368 {
2369   clutter_actor_set_background_color (CLUTTER_ACTOR (stage), color);
2370
2371   g_object_notify (G_OBJECT (stage), "color");
2372 }
2373
2374 /**
2375  * clutter_stage_get_color:
2376  * @stage: A #ClutterStage
2377  * @color: (out caller-allocates): return location for a #ClutterColor
2378  *
2379  * Retrieves the stage color.
2380  *
2381  * Deprecated: 1.10: Use clutter_actor_get_background_color() instead.
2382  */
2383 void
2384 clutter_stage_get_color (ClutterStage *stage,
2385                          ClutterColor *color)
2386 {
2387   clutter_actor_get_background_color (CLUTTER_ACTOR (stage), color);
2388 }
2389
2390 static void
2391 clutter_stage_set_perspective_internal (ClutterStage       *stage,
2392                                         ClutterPerspective *perspective)
2393 {
2394   ClutterStagePrivate *priv = stage->priv;
2395
2396   if (priv->perspective.fovy == perspective->fovy &&
2397       priv->perspective.aspect == perspective->aspect &&
2398       priv->perspective.z_near == perspective->z_near &&
2399       priv->perspective.z_far == perspective->z_far)
2400     return;
2401
2402   priv->perspective = *perspective;
2403
2404   cogl_matrix_init_identity (&priv->projection);
2405   cogl_matrix_perspective (&priv->projection,
2406                            priv->perspective.fovy,
2407                            priv->perspective.aspect,
2408                            priv->perspective.z_near,
2409                            priv->perspective.z_far);
2410   cogl_matrix_get_inverse (&priv->projection,
2411                            &priv->inverse_projection);
2412
2413   priv->dirty_projection = TRUE;
2414   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
2415 }
2416
2417 /**
2418  * clutter_stage_set_perspective:
2419  * @stage: A #ClutterStage
2420  * @perspective: A #ClutterPerspective
2421  *
2422  * Sets the stage perspective. Using this function is not recommended
2423  * because it will disable Clutter's attempts to generate an
2424  * appropriate perspective based on the size of the stage.
2425  */
2426 void
2427 clutter_stage_set_perspective (ClutterStage       *stage,
2428                                ClutterPerspective *perspective)
2429 {
2430   ClutterStagePrivate *priv;
2431
2432   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2433   g_return_if_fail (perspective != NULL);
2434   g_return_if_fail (perspective->z_far - perspective->z_near != 0);
2435
2436   priv = stage->priv;
2437
2438   /* If the application ever calls this function then we'll stop
2439      automatically updating the perspective when the stage changes
2440      size */
2441   priv->has_custom_perspective = TRUE;
2442
2443   clutter_stage_set_perspective_internal (stage, perspective);
2444 }
2445
2446 /**
2447  * clutter_stage_get_perspective:
2448  * @stage: A #ClutterStage
2449  * @perspective: (out caller-allocates) (allow-none): return location for a
2450  *   #ClutterPerspective
2451  *
2452  * Retrieves the stage perspective.
2453  */
2454 void
2455 clutter_stage_get_perspective (ClutterStage       *stage,
2456                                ClutterPerspective *perspective)
2457 {
2458   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2459   g_return_if_fail (perspective != NULL);
2460
2461   *perspective = stage->priv->perspective;
2462 }
2463
2464 /*
2465  * clutter_stage_get_projection_matrix:
2466  * @stage: A #ClutterStage
2467  * @projection: return location for a #CoglMatrix representing the
2468  *              perspective projection applied to actors on the given
2469  *              @stage.
2470  *
2471  * Retrieves the @stage's projection matrix. This is derived from the
2472  * current perspective set using clutter_stage_set_perspective().
2473  *
2474  * Since: 1.6
2475  */
2476 void
2477 _clutter_stage_get_projection_matrix (ClutterStage *stage,
2478                                       CoglMatrix *projection)
2479 {
2480   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2481   g_return_if_fail (projection != NULL);
2482
2483   *projection = stage->priv->projection;
2484 }
2485
2486 /* This simply provides a simple mechanism for us to ensure that
2487  * the projection matrix gets re-asserted before painting.
2488  *
2489  * This is used when switching between multiple stages */
2490 void
2491 _clutter_stage_dirty_projection (ClutterStage *stage)
2492 {
2493   stage->priv->dirty_projection = TRUE;
2494 }
2495
2496 /*
2497  * clutter_stage_set_viewport:
2498  * @stage: A #ClutterStage
2499  * @x: The X postition to render the stage at, in window coordinates
2500  * @y: The Y position to render the stage at, in window coordinates
2501  * @width: The width to render the stage at, in window coordinates
2502  * @height: The height to render the stage at, in window coordinates
2503  *
2504  * Sets the stage viewport. The viewport defines a final scale and
2505  * translation of your rendered stage and actors. This lets you render
2506  * your stage into a subregion of the stage window or you could use it to
2507  * pan a subregion of the stage if your stage window is smaller then
2508  * the stage. (XXX: currently this isn't possible)
2509  *
2510  * Unlike a scale and translation done using the modelview matrix this
2511  * is done after everything has had perspective projection applied, so
2512  * for example if you were to pan across a subregion of the stage using
2513  * the viewport then you would not see a change in perspective for the
2514  * actors on the stage.
2515  *
2516  * Normally the stage viewport will automatically track the size of the
2517  * stage window with no offset so the stage will fill your window. This
2518  * behaviour can be changed with the "viewport-mimics-window" property
2519  * which will automatically be set to FALSE if you use this API. If
2520  * you want to revert to the original behaviour then you should set
2521  * this property back to %TRUE using
2522  * clutter_stage_set_viewport_mimics_window().
2523  * (XXX: If we were to make this API public then we might want to do
2524  *  add that property.)
2525  *
2526  * Note: currently this interface only support integer precision
2527  * offsets and sizes for viewports but the interface takes floats because
2528  * OpenGL 4.0 has introduced floating point viewports which we might
2529  * want to expose via this API eventually.
2530  *
2531  * Since: 1.6
2532  */
2533 void
2534 _clutter_stage_set_viewport (ClutterStage *stage,
2535                              float         x,
2536                              float         y,
2537                              float         width,
2538                              float         height)
2539 {
2540   ClutterStagePrivate *priv;
2541
2542   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2543
2544   priv = stage->priv;
2545
2546
2547   if (x == priv->viewport[0] &&
2548       y == priv->viewport[1] &&
2549       width == priv->viewport[2] &&
2550       height == priv->viewport[3])
2551     return;
2552
2553   priv->viewport[0] = x;
2554   priv->viewport[1] = y;
2555   priv->viewport[2] = width;
2556   priv->viewport[3] = height;
2557
2558   priv->dirty_viewport = TRUE;
2559
2560   queue_full_redraw (stage);
2561 }
2562
2563 /* This simply provides a simple mechanism for us to ensure that
2564  * the viewport gets re-asserted before next painting.
2565  *
2566  * This is used when switching between multiple stages */
2567 void
2568 _clutter_stage_dirty_viewport (ClutterStage *stage)
2569 {
2570   stage->priv->dirty_viewport = TRUE;
2571 }
2572
2573 /*
2574  * clutter_stage_get_viewport:
2575  * @stage: A #ClutterStage
2576  * @x: A location for the X position where the stage is rendered,
2577  *     in window coordinates.
2578  * @y: A location for the Y position where the stage is rendered,
2579  *     in window coordinates.
2580  * @width: A location for the width the stage is rendered at,
2581  *         in window coordinates.
2582  * @height: A location for the height the stage is rendered at,
2583  *          in window coordinates.
2584  *
2585  * Returns the viewport offset and size set using
2586  * clutter_stage_set_viewport() or if the "viewport-mimics-window" property
2587  * is TRUE then @x and @y will be set to 0 and @width and @height will equal
2588  * the width if the stage window.
2589  *
2590  * Since: 1.6
2591  */
2592 void
2593 _clutter_stage_get_viewport (ClutterStage *stage,
2594                              float        *x,
2595                              float        *y,
2596                              float        *width,
2597                              float        *height)
2598 {
2599   ClutterStagePrivate *priv;
2600
2601   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2602
2603   priv = stage->priv;
2604
2605   *x = priv->viewport[0];
2606   *y = priv->viewport[1];
2607   *width = priv->viewport[2];
2608   *height = priv->viewport[3];
2609 }
2610
2611 /**
2612  * clutter_stage_set_fullscreen:
2613  * @stage: a #ClutterStage
2614  * @fullscreen: %TRUE to to set the stage fullscreen
2615  *
2616  * Asks to place the stage window in the fullscreen or unfullscreen
2617  * states.
2618  *
2619  ( Note that you shouldn't assume the window is definitely full screen
2620  * afterward, because other entities (e.g. the user or window manager)
2621  * could unfullscreen it again, and not all window managers honor
2622  * requests to fullscreen windows.
2623  *
2624  * If you want to receive notification of the fullscreen state you
2625  * should either use the #ClutterStage::fullscreen and
2626  * #ClutterStage::unfullscreen signals, or use the notify signal
2627  * for the #ClutterStage:fullscreen-set property
2628  *
2629  * Since: 1.0
2630  */
2631 void
2632 clutter_stage_set_fullscreen (ClutterStage *stage,
2633                               gboolean      fullscreen)
2634 {
2635   ClutterStagePrivate *priv;
2636
2637   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2638
2639   priv = stage->priv;
2640
2641   if (priv->is_fullscreen != fullscreen)
2642     {
2643       ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
2644       ClutterStageWindowIface *iface;
2645
2646       iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
2647
2648       /* Only set if backend implements.
2649        *
2650        * Also see clutter_stage_event() for setting priv->is_fullscreen
2651        * on state change event.
2652        */
2653       if (iface->set_fullscreen)
2654         iface->set_fullscreen (impl, fullscreen);
2655     }
2656
2657   /* If the backend did fullscreen the stage window then we need to resize
2658    * the stage and update its viewport so we queue a relayout.  Note: if the
2659    * fullscreen request is handled asynchronously we can't rely on this
2660    * queue_relayout to update the viewport, but for example the X backend
2661    * will recieve a ConfigureNotify after a successful resize which is how
2662    * we ensure the viewport is updated on X.
2663    */
2664   clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
2665 }
2666
2667 /**
2668  * clutter_stage_get_fullscreen:
2669  * @stage: a #ClutterStage
2670  *
2671  * Retrieves whether the stage is full screen or not
2672  *
2673  * Return value: %TRUE if the stage is full screen
2674  *
2675  * Since: 1.0
2676  */
2677 gboolean
2678 clutter_stage_get_fullscreen (ClutterStage *stage)
2679 {
2680   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
2681
2682   return stage->priv->is_fullscreen;
2683 }
2684
2685 /**
2686  * clutter_stage_set_user_resizable:
2687  * @stage: a #ClutterStage
2688  * @resizable: whether the stage should be user resizable.
2689  *
2690  * Sets if the stage is resizable by user interaction (e.g. via
2691  * window manager controls)
2692  *
2693  * Since: 0.4
2694  */
2695 void
2696 clutter_stage_set_user_resizable (ClutterStage *stage,
2697                                   gboolean      resizable)
2698 {
2699   ClutterStagePrivate *priv;
2700
2701   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2702
2703   priv = stage->priv;
2704
2705   if (clutter_feature_available (CLUTTER_FEATURE_STAGE_USER_RESIZE)
2706       && priv->is_user_resizable != resizable)
2707     {
2708       ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
2709       ClutterStageWindowIface *iface;
2710
2711       iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
2712       if (iface->set_user_resizable)
2713         {
2714           priv->is_user_resizable = resizable;
2715
2716           iface->set_user_resizable (impl, resizable);
2717
2718           g_object_notify (G_OBJECT (stage), "user-resizable");
2719         }
2720     }
2721 }
2722
2723 /**
2724  * clutter_stage_get_user_resizable:
2725  * @stage: a #ClutterStage
2726  *
2727  * Retrieves the value set with clutter_stage_set_user_resizable().
2728  *
2729  * Return value: %TRUE if the stage is resizable by the user.
2730  *
2731  * Since: 0.4
2732  */
2733 gboolean
2734 clutter_stage_get_user_resizable (ClutterStage *stage)
2735 {
2736   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
2737
2738   return stage->priv->is_user_resizable;
2739 }
2740
2741 /**
2742  * clutter_stage_show_cursor:
2743  * @stage: a #ClutterStage
2744  *
2745  * Shows the cursor on the stage window
2746  */
2747 void
2748 clutter_stage_show_cursor (ClutterStage *stage)
2749 {
2750   ClutterStagePrivate *priv;
2751
2752   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2753
2754   priv = stage->priv;
2755   if (!priv->is_cursor_visible)
2756     {
2757       ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
2758       ClutterStageWindowIface *iface;
2759
2760       iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
2761       if (iface->set_cursor_visible)
2762         {
2763           priv->is_cursor_visible = TRUE;
2764
2765           iface->set_cursor_visible (impl, TRUE);
2766
2767           g_object_notify (G_OBJECT (stage), "cursor-visible");
2768         }
2769     }
2770 }
2771
2772 /**
2773  * clutter_stage_hide_cursor:
2774  * @stage: a #ClutterStage
2775  *
2776  * Makes the cursor invisible on the stage window
2777  *
2778  * Since: 0.4
2779  */
2780 void
2781 clutter_stage_hide_cursor (ClutterStage *stage)
2782 {
2783   ClutterStagePrivate *priv;
2784
2785   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2786
2787   priv = stage->priv;
2788   if (priv->is_cursor_visible)
2789     {
2790       ClutterStageWindow *impl = CLUTTER_STAGE_WINDOW (priv->impl);
2791       ClutterStageWindowIface *iface;
2792
2793       iface = CLUTTER_STAGE_WINDOW_GET_IFACE (impl);
2794       if (iface->set_cursor_visible)
2795         {
2796           priv->is_cursor_visible = FALSE;
2797
2798           iface->set_cursor_visible (impl, FALSE);
2799
2800           g_object_notify (G_OBJECT (stage), "cursor-visible");
2801         }
2802     }
2803 }
2804
2805 /**
2806  * clutter_stage_read_pixels:
2807  * @stage: A #ClutterStage
2808  * @x: x coordinate of the first pixel that is read from stage
2809  * @y: y coordinate of the first pixel that is read from stage
2810  * @width: Width dimention of pixels to be read, or -1 for the
2811  *   entire stage width
2812  * @height: Height dimention of pixels to be read, or -1 for the
2813  *   entire stage height
2814  *
2815  * Makes a screenshot of the stage in RGBA 8bit data, returns a
2816  * linear buffer with @width * 4 as rowstride.
2817  *
2818  * The alpha data contained in the returned buffer is driver-dependent,
2819  * and not guaranteed to hold any sensible value.
2820  *
2821  * Return value: (array): a pointer to newly allocated memory with the buffer
2822  *   or %NULL if the read failed. Use g_free() on the returned data
2823  *   to release the resources it has allocated.
2824  */
2825 guchar *
2826 clutter_stage_read_pixels (ClutterStage *stage,
2827                            gint          x,
2828                            gint          y,
2829                            gint          width,
2830                            gint          height)
2831 {
2832   ClutterGeometry geom;
2833   guchar *pixels;
2834
2835   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
2836
2837   /* Force a redraw of the stage before reading back pixels */
2838   clutter_stage_ensure_current (stage);
2839   clutter_actor_paint (CLUTTER_ACTOR (stage));
2840
2841   clutter_actor_get_allocation_geometry (CLUTTER_ACTOR (stage), &geom);
2842
2843   if (width < 0)
2844     width = geom.width;
2845
2846   if (height < 0)
2847     height = geom.height;
2848
2849   pixels = g_malloc (height * width * 4);
2850
2851   cogl_read_pixels (x, y, width, height,
2852                     COGL_READ_PIXELS_COLOR_BUFFER,
2853                     COGL_PIXEL_FORMAT_RGBA_8888,
2854                     pixels);
2855
2856   return pixels;
2857 }
2858
2859 /**
2860  * clutter_stage_get_actor_at_pos:
2861  * @stage: a #ClutterStage
2862  * @pick_mode: how the scene graph should be painted
2863  * @x: X coordinate to check
2864  * @y: Y coordinate to check
2865  *
2866  * Checks the scene at the coordinates @x and @y and returns a pointer
2867  * to the #ClutterActor at those coordinates.
2868  *
2869  * By using @pick_mode it is possible to control which actors will be
2870  * painted and thus available.
2871  *
2872  * Return value: (transfer none): the actor at the specified coordinates,
2873  *   if any
2874  */
2875 ClutterActor *
2876 clutter_stage_get_actor_at_pos (ClutterStage    *stage,
2877                                 ClutterPickMode  pick_mode,
2878                                 gint             x,
2879                                 gint             y)
2880 {
2881   return _clutter_stage_do_pick (stage, x, y, pick_mode);
2882 }
2883
2884 /**
2885  * clutter_stage_event:
2886  * @stage: a #ClutterStage
2887  * @event: a #ClutterEvent
2888  *
2889  * This function is used to emit an event on the main stage.
2890  *
2891  * You should rarely need to use this function, except for
2892  * synthetised events.
2893  *
2894  * Return value: the return value from the signal emission
2895  *
2896  * Since: 0.4
2897  */
2898 gboolean
2899 clutter_stage_event (ClutterStage *stage,
2900                      ClutterEvent *event)
2901 {
2902   ClutterStagePrivate *priv;
2903
2904   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
2905   g_return_val_if_fail (event != NULL, FALSE);
2906
2907   priv = stage->priv;
2908
2909   if (event->type == CLUTTER_DELETE)
2910     {
2911       gboolean retval = FALSE;
2912
2913       g_signal_emit_by_name (stage, "event", event, &retval);
2914
2915       if (!retval)
2916         g_signal_emit_by_name (stage, "delete-event", event, &retval);
2917
2918       return retval;
2919     }
2920
2921   if (event->type != CLUTTER_STAGE_STATE)
2922     return FALSE;
2923
2924   /* emit raw event */
2925   if (clutter_actor_event (CLUTTER_ACTOR (stage), event, FALSE))
2926     return TRUE;
2927
2928   if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_FULLSCREEN)
2929     {
2930       if (event->stage_state.new_state & CLUTTER_STAGE_STATE_FULLSCREEN)
2931         {
2932           priv->is_fullscreen = TRUE;
2933           g_signal_emit (stage, stage_signals[FULLSCREEN], 0);
2934
2935           g_object_notify (G_OBJECT (stage), "fullscreen-set");
2936         }
2937       else
2938         {
2939           priv->is_fullscreen = FALSE;
2940           g_signal_emit (stage, stage_signals[UNFULLSCREEN], 0);
2941
2942           g_object_notify (G_OBJECT (stage), "fullscreen-set");
2943         }
2944     }
2945
2946   if (event->stage_state.changed_mask & CLUTTER_STAGE_STATE_ACTIVATED)
2947     {
2948       if (event->stage_state.new_state & CLUTTER_STAGE_STATE_ACTIVATED)
2949         g_signal_emit (stage, stage_signals[ACTIVATE], 0);
2950       else
2951         g_signal_emit (stage, stage_signals[DEACTIVATE], 0);
2952     }
2953
2954   return TRUE;
2955 }
2956
2957 /**
2958  * clutter_stage_set_title
2959  * @stage: A #ClutterStage
2960  * @title: A utf8 string for the stage windows title.
2961  *
2962  * Sets the stage title.
2963  *
2964  * Since: 0.4
2965  **/
2966 void
2967 clutter_stage_set_title (ClutterStage       *stage,
2968                          const gchar        *title)
2969 {
2970   ClutterStagePrivate *priv;
2971   ClutterStageWindow *impl;
2972
2973   g_return_if_fail (CLUTTER_IS_STAGE (stage));
2974
2975   priv = stage->priv;
2976
2977   g_free (priv->title);
2978   priv->title = g_strdup (title);
2979
2980   impl = CLUTTER_STAGE_WINDOW (priv->impl);
2981   if (CLUTTER_STAGE_WINDOW_GET_IFACE(impl)->set_title != NULL)
2982     CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->set_title (impl, priv->title);
2983
2984   g_object_notify (G_OBJECT (stage), "title");
2985 }
2986
2987 /**
2988  * clutter_stage_get_title
2989  * @stage: A #ClutterStage
2990  *
2991  * Gets the stage title.
2992  *
2993  * Return value: pointer to the title string for the stage. The
2994  * returned string is owned by the actor and should not
2995  * be modified or freed.
2996  *
2997  * Since: 0.4
2998  **/
2999 const gchar *
3000 clutter_stage_get_title (ClutterStage       *stage)
3001 {
3002   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
3003
3004   return stage->priv->title;
3005 }
3006
3007 static void
3008 on_key_focus_destroy (ClutterActor *actor,
3009                       ClutterStage *stage)
3010 {
3011   /* unset the key focus */
3012   clutter_stage_set_key_focus (stage, NULL);
3013 }
3014
3015 /**
3016  * clutter_stage_set_key_focus:
3017  * @stage: the #ClutterStage
3018  * @actor: (allow-none): the actor to set key focus to, or %NULL
3019  *
3020  * Sets the key focus on @actor. An actor with key focus will receive
3021  * all the key events. If @actor is %NULL, the stage will receive
3022  * focus.
3023  *
3024  * Since: 0.6
3025  */
3026 void
3027 clutter_stage_set_key_focus (ClutterStage *stage,
3028                              ClutterActor *actor)
3029 {
3030   ClutterStagePrivate *priv;
3031
3032   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3033   g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
3034
3035   priv = stage->priv;
3036
3037   /* avoid emitting signals and notifications if we're setting the same
3038    * actor as the key focus
3039    */
3040   if (priv->key_focused_actor == actor)
3041     return;
3042
3043   if (priv->key_focused_actor != NULL)
3044     {
3045       ClutterActor *old_focused_actor;
3046
3047       old_focused_actor = priv->key_focused_actor;
3048
3049       /* set key_focused_actor to NULL before emitting the signal or someone
3050        * might hide the previously focused actor in the signal handler and we'd
3051        * get re-entrant call and get glib critical from g_object_weak_unref
3052        */
3053       g_signal_handlers_disconnect_by_func (priv->key_focused_actor,
3054                                             G_CALLBACK (on_key_focus_destroy),
3055                                             stage);
3056       priv->key_focused_actor = NULL;
3057
3058       g_signal_emit_by_name (old_focused_actor, "key-focus-out");
3059     }
3060   else
3061     g_signal_emit_by_name (stage, "key-focus-out");
3062
3063   /* Note, if someone changes key focus in focus-out signal handler we'd be
3064    * overriding the latter call below moving the focus where it was originally
3065    * intended. The order of events would be:
3066    *   1st focus-out, 2nd focus-out (on stage), 2nd focus-in, 1st focus-in
3067    */
3068   if (actor != NULL)
3069     {
3070       priv->key_focused_actor = actor;
3071
3072       g_signal_connect (actor,
3073                         "destroy", G_CALLBACK (on_key_focus_destroy),
3074                         stage);
3075       g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
3076     }
3077   else
3078     g_signal_emit_by_name (stage, "key-focus-in");
3079
3080   g_object_notify (G_OBJECT (stage), "key-focus");
3081 }
3082
3083 /**
3084  * clutter_stage_get_key_focus:
3085  * @stage: the #ClutterStage
3086  *
3087  * Retrieves the actor that is currently under key focus.
3088  *
3089  * Return value: (transfer none): the actor with key focus, or the stage
3090  *
3091  * Since: 0.6
3092  */
3093 ClutterActor *
3094 clutter_stage_get_key_focus (ClutterStage *stage)
3095 {
3096   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
3097
3098   if (stage->priv->key_focused_actor)
3099     return stage->priv->key_focused_actor;
3100
3101   return CLUTTER_ACTOR (stage);
3102 }
3103
3104 /**
3105  * clutter_stage_get_use_fog:
3106  * @stage: the #ClutterStage
3107  *
3108  * Gets whether the depth cueing effect is enabled on @stage.
3109  *
3110  * Return value: %TRUE if the depth cueing effect is enabled
3111  *
3112  * Since: 0.6
3113  *
3114  * Deprecated: 1.10: This function will always return %FALSE
3115  */
3116 gboolean
3117 clutter_stage_get_use_fog (ClutterStage *stage)
3118 {
3119   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
3120
3121   return stage->priv->use_fog;
3122 }
3123
3124 /**
3125  * clutter_stage_set_use_fog:
3126  * @stage: the #ClutterStage
3127  * @fog: %TRUE for enabling the depth cueing effect
3128  *
3129  * Sets whether the depth cueing effect on the stage should be enabled
3130  * or not.
3131  *
3132  * Depth cueing is a 3D effect that makes actors farther away from the
3133  * viewing point less opaque, by fading them with the stage color.
3134
3135  * The parameters of the GL fog used can be changed using the
3136  * clutter_stage_set_fog() function.
3137  *
3138  * Since: 0.6
3139  *
3140  * Deprecated: 1.10: Calling this function produces no visible effect
3141  */
3142 void
3143 clutter_stage_set_use_fog (ClutterStage *stage,
3144                            gboolean      fog)
3145 {
3146 }
3147
3148 /**
3149  * clutter_stage_set_fog:
3150  * @stage: the #ClutterStage
3151  * @fog: a #ClutterFog structure
3152  *
3153  * Sets the fog (also known as "depth cueing") settings for the @stage.
3154  *
3155  * A #ClutterStage will only use a linear fog progression, which
3156  * depends solely on the distance from the viewer. The cogl_set_fog()
3157  * function in COGL exposes more of the underlying implementation,
3158  * and allows changing the for progression function. It can be directly
3159  * used by disabling the #ClutterStage:use-fog property and connecting
3160  * a signal handler to the #ClutterActor::paint signal on the @stage,
3161  * like:
3162  *
3163  * |[
3164  *   clutter_stage_set_use_fog (stage, FALSE);
3165  *   g_signal_connect (stage, "paint", G_CALLBACK (on_stage_paint), NULL);
3166  * ]|
3167  *
3168  * The paint signal handler will call cogl_set_fog() with the
3169  * desired settings:
3170  *
3171  * |[
3172  *   static void
3173  *   on_stage_paint (ClutterActor *actor)
3174  *   {
3175  *     ClutterColor stage_color = { 0, };
3176  *     CoglColor fog_color = { 0, };
3177  *
3178  *     /&ast; set the fog color to the stage background color &ast;/
3179  *     clutter_stage_get_color (CLUTTER_STAGE (actor), &amp;stage_color);
3180  *     cogl_color_init_from_4ub (&amp;fog_color,
3181  *                               stage_color.red,
3182  *                               stage_color.green,
3183  *                               stage_color.blue,
3184  *                               stage_color.alpha);
3185  *
3186  *     /&ast; enable fog &ast;/
3187  *     cogl_set_fog (&amp;fog_color,
3188  *                   COGL_FOG_MODE_EXPONENTIAL, /&ast; mode &ast;/
3189  *                   0.5,                       /&ast; density &ast;/
3190  *                   5.0, 30.0);                /&ast; z_near and z_far &ast;/
3191  *   }
3192  * ]|
3193  *
3194  * <note>The fogging functions only work correctly when the visible actors use
3195  * unmultiplied alpha colors. By default Cogl will premultiply textures and
3196  * cogl_set_source_color() will premultiply colors, so unless you explicitly
3197  * load your textures requesting an unmultiplied internal format and use
3198  * cogl_material_set_color() you can only use fogging with fully opaque actors.
3199  * Support for premultiplied colors will improve in the future when we can
3200  * depend on fragment shaders.</note>
3201  *
3202  * Since: 0.6
3203  *
3204  * Deprecated: 1.10: Fog settings are ignored.
3205  */
3206 void
3207 clutter_stage_set_fog (ClutterStage *stage,
3208                        ClutterFog   *fog)
3209 {
3210 }
3211
3212 /**
3213  * clutter_stage_get_fog:
3214  * @stage: the #ClutterStage
3215  * @fog: (out): return location for a #ClutterFog structure
3216  *
3217  * Retrieves the current depth cueing settings from the stage.
3218  *
3219  * Since: 0.6
3220  *
3221  * Deprecated: 1.10: This function will always return the default
3222  *   values of #ClutterFog
3223  */
3224 void
3225 clutter_stage_get_fog (ClutterStage *stage,
3226                         ClutterFog   *fog)
3227 {
3228   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3229   g_return_if_fail (fog != NULL);
3230
3231   *fog = stage->priv->fog;
3232 }
3233
3234 /*** Perspective boxed type ******/
3235
3236 static gpointer
3237 clutter_perspective_copy (gpointer data)
3238 {
3239   if (G_LIKELY (data))
3240     return g_slice_dup (ClutterPerspective, data);
3241
3242   return NULL;
3243 }
3244
3245 static void
3246 clutter_perspective_free (gpointer data)
3247 {
3248   if (G_LIKELY (data))
3249     g_slice_free (ClutterPerspective, data);
3250 }
3251
3252 G_DEFINE_BOXED_TYPE (ClutterPerspective, clutter_perspective,
3253                      clutter_perspective_copy,
3254                      clutter_perspective_free);
3255
3256 static gpointer
3257 clutter_fog_copy (gpointer data)
3258 {
3259   if (G_LIKELY (data))
3260     return g_slice_dup (ClutterFog, data);
3261
3262   return NULL;
3263 }
3264
3265 static void
3266 clutter_fog_free (gpointer data)
3267 {
3268   if (G_LIKELY (data))
3269     g_slice_free (ClutterFog, data);
3270 }
3271
3272 G_DEFINE_BOXED_TYPE (ClutterFog, clutter_fog, clutter_fog_copy, clutter_fog_free);
3273
3274 /**
3275  * clutter_stage_new:
3276  *
3277  * Creates a new, non-default stage. A non-default stage is a new
3278  * top-level actor which can be used as another container. It works
3279  * exactly like the default stage, but while clutter_stage_get_default()
3280  * will always return the same instance, you will have to keep a pointer
3281  * to any #ClutterStage returned by clutter_stage_new().
3282  *
3283  * The ability to support multiple stages depends on the current
3284  * backend. Use clutter_feature_available() and
3285  * %CLUTTER_FEATURE_STAGE_MULTIPLE to check at runtime whether a
3286  * backend supports multiple stages.
3287  *
3288  * Return value: a new stage, or %NULL if the default backend does
3289  *   not support multiple stages. Use clutter_actor_destroy() to
3290  *   programmatically close the returned stage.
3291  *
3292  * Since: 0.8
3293  */
3294 ClutterActor *
3295 clutter_stage_new (void)
3296 {
3297   return g_object_new (CLUTTER_TYPE_STAGE, NULL);
3298 }
3299
3300 /**
3301  * clutter_stage_ensure_current:
3302  * @stage: the #ClutterStage
3303  *
3304  * This function essentially makes sure the right GL context is
3305  * current for the passed stage. It is not intended to
3306  * be used by applications.
3307  *
3308  * Since: 0.8
3309  */
3310 void
3311 clutter_stage_ensure_current (ClutterStage *stage)
3312 {
3313   ClutterBackend *backend;
3314
3315   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3316
3317   backend = clutter_get_default_backend ();
3318   _clutter_backend_ensure_context (backend, stage);
3319 }
3320
3321 /**
3322  * clutter_stage_ensure_viewport:
3323  * @stage: a #ClutterStage
3324  *
3325  * Ensures that the GL viewport is updated with the current
3326  * stage window size.
3327  *
3328  * This function will queue a redraw of @stage.
3329  *
3330  * This function should not be called by applications; it is used
3331  * when embedding a #ClutterStage into a toolkit with another
3332  * windowing system, like GTK+.
3333  *
3334  * Since: 1.0
3335  */
3336 void
3337 clutter_stage_ensure_viewport (ClutterStage *stage)
3338 {
3339   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3340
3341   _clutter_stage_dirty_viewport (stage);
3342
3343   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
3344 }
3345
3346 /* This calculates a distance into the view frustum to position the
3347  * stage so there is a decent amount of space to position geometry
3348  * between the stage and the near clipping plane.
3349  *
3350  * Some awkward issues with this problem are:
3351  * - It's not possible to have a gap as large as the stage size with
3352  *   a fov > 53° which is basically always the case since the default
3353  *   fov is 60°.
3354  *    - This can be deduced if you consider that this requires a
3355  *      triangle as wide as it is deep to fit in the frustum in front
3356  *      of the z_near plane. That triangle will always have an angle
3357  *      of 53.13° at the point sitting on the z_near plane, but if the
3358  *      frustum has a wider fov angle the left/right clipping planes
3359  *      can never converge with the two corners of our triangle no
3360  *      matter what size the triangle has.
3361  * - With a fov > 53° there is a trade off between maximizing the gap
3362  *   size relative to the stage size but not loosing depth precision.
3363  * - Perhaps ideally we wouldn't just consider the fov on the y-axis
3364  *   that is usually used to define a perspective, we would consider
3365  *   the fov of the axis with the largest stage size so the gap would
3366  *   accommodate that size best.
3367  *
3368  * After going around in circles a few times with how to handle these
3369  * issues, we decided in the end to go for the simplest solution to
3370  * start with instead of an elaborate function that handles arbitrary
3371  * fov angles that we currently have no use-case for.
3372  *
3373  * The solution assumes a fovy of 60° and for that case gives a gap
3374  * that's 85% of the stage height. We can consider more elaborate
3375  * functions if necessary later.
3376  *
3377  * One guide we had to steer the gap size we support is the
3378  * interactive test, test-texture-quality which expects to animate an
3379  * actor to +400 on the z axis with a stage size of 640x480. A gap
3380  * that's 85% of the stage height gives a gap of 408 in that case.
3381  */
3382 static float
3383 calculate_z_translation (float z_near)
3384 {
3385   /* This solution uses fairly basic trigonometry, but is seems worth
3386    * clarifying the particular geometry we are looking at in-case
3387    * anyone wants to develop this further later. Not sure how well an
3388    * ascii diagram is going to work :-)
3389    *
3390    *    |--- stage_height ---|
3391    *    |     stage line     |
3392    *   ╲━━━━━━━━━━━━━━━━━━━━━╱------------
3393    *    ╲.  (2)   │        .╱       |   |
3394    *   C ╲ .      │      . ╱     gap|   |
3395    * =0.5°╲  . a  │    .  ╱         |   |
3396    *      b╲(1). D│  .   ╱          |   |
3397    *        ╲   B.│.    ╱near plane |   |
3398    *      A= ╲━━━━━━━━━╱-------------   |
3399    *     120° ╲ c │   ╱  |            z_2d
3400    *           ╲  │  ╱  z_near          |
3401    *       left ╲ │ ╱    |              |
3402    *       clip  60°fovy |              |
3403    *       plane  ╳----------------------
3404    *              |
3405    *              |
3406    *         origin line
3407    *
3408    * The area of interest is the triangle labeled (1) at the top left
3409    * marked with the ... line (a) from where the origin line crosses
3410    * the near plane to the top left where the stage line cross the
3411    * left clip plane.
3412    *
3413    * The sides of the triangle are a, b and c and the corresponding
3414    * angles opposite those sides are A, B and C.
3415    *
3416    * The angle of C is what trades off the gap size we have relative
3417    * to the stage size vs the depth precision we have.
3418    *
3419    * As mentioned above we arove at the angle for C is by working
3420    * backwards from how much space we want for test-texture-quality.
3421    * With a stage_height of 480 we want a gap > 400, ideally we also
3422    * wanted a somewhat round number as a percentage of the height for
3423    * documentation purposes. ~87% or a gap of ~416 is the limit
3424    * because that's where we approach a C angle of 0° and effectively
3425    * loose all depth precision.
3426    *
3427    * So for our test app with a stage_height of 480 if we aim for a
3428    * gap of 408 (85% of 480) we can get the angle D as
3429    * atan (stage_height/2/408) = 30.5°.
3430    *
3431    * That gives us the angle for B as 90° - 30.5° = 59.5°
3432    *
3433    * We can already determine that A has an angle of (fovy/2 + 90°) =
3434    * 120°
3435    *
3436    * Therefore C = 180 - A - B = 0.5°
3437    *
3438    * The length of c = z_near * tan (30°)
3439    *
3440    * Now we can use the rule a/SinA = c/SinC to calculate the
3441    * length of a. After some rearranging that gives us:
3442    *
3443    *      a              c
3444    *  ----------  =  ----------
3445    *  sin (120°)     sin (0.5°)
3446    *
3447    *      c * sin (120°)
3448    *  a = --------------
3449    *        sin (0.5°)
3450    *
3451    * And with that we can determine z_2d = cos (D) * a =
3452    * cos (30.5°) * a + z_near:
3453    *
3454    *         c * sin (120°) * cos (30.5°)
3455    *  z_2d = --------------------------- + z_near
3456    *                 sin (0.5°)
3457    */
3458 #define _DEG_TO_RAD (G_PI / 180.0)
3459   return z_near * tanf (30.0f * _DEG_TO_RAD) *
3460          sinf (120.0f * _DEG_TO_RAD) * cosf (30.5f * _DEG_TO_RAD) /
3461          sinf (0.5f * _DEG_TO_RAD) +
3462          z_near;
3463 #undef _DEG_TO_RAD
3464    /* We expect the compiler should boil this down to z_near * CONSTANT */
3465 }
3466
3467 void
3468 _clutter_stage_maybe_setup_viewport (ClutterStage *stage)
3469 {
3470   ClutterStagePrivate *priv = stage->priv;
3471
3472   if (priv->dirty_viewport)
3473     {
3474       ClutterPerspective perspective;
3475       float z_2d;
3476
3477       CLUTTER_NOTE (PAINT,
3478                     "Setting up the viewport { w:%f, h:%f }",
3479                     priv->viewport[2], priv->viewport[3]);
3480
3481       cogl_set_viewport (priv->viewport[0],
3482                          priv->viewport[1],
3483                          priv->viewport[2],
3484                          priv->viewport[3]);
3485
3486       perspective = priv->perspective;
3487
3488       /* Ideally we want to regenerate the perspective matrix whenever
3489        * the size changes but if the user has provided a custom matrix
3490        * then we don't want to override it */
3491       if (!priv->has_custom_perspective)
3492         {
3493           perspective.aspect = priv->viewport[2] / priv->viewport[3];
3494           z_2d = calculate_z_translation (perspective.z_near);
3495
3496 #define _DEG_TO_RAD (G_PI / 180.0)
3497           /* NB: z_2d is only enough room for 85% of the stage_height between
3498            * the stage and the z_near plane. For behind the stage plane we
3499            * want a more consistent gap of 10 times the stage_height before
3500            * hitting the far plane so we calculate that relative to the final
3501            * height of the stage plane at the z_2d_distance we got... */
3502           perspective.z_far = z_2d +
3503             tanf ((perspective.fovy / 2.0f) * _DEG_TO_RAD) * z_2d * 20.0f;
3504 #undef _DEG_TO_RAD
3505
3506           clutter_stage_set_perspective_internal (stage, &perspective);
3507         }
3508       else
3509         z_2d = calculate_z_translation (perspective.z_near);
3510
3511       cogl_matrix_init_identity (&priv->view);
3512       cogl_matrix_view_2d_in_perspective (&priv->view,
3513                                           perspective.fovy,
3514                                           perspective.aspect,
3515                                           perspective.z_near,
3516                                           z_2d,
3517                                           priv->viewport[2],
3518                                           priv->viewport[3]);
3519
3520       priv->dirty_viewport = FALSE;
3521     }
3522
3523   if (priv->dirty_projection)
3524     {
3525       cogl_set_projection_matrix (&priv->projection);
3526
3527       priv->dirty_projection = FALSE;
3528     }
3529 }
3530
3531 /**
3532  * clutter_stage_ensure_redraw:
3533  * @stage: a #ClutterStage
3534  *
3535  * Ensures that @stage is redrawn
3536  *
3537  * This function should not be called by applications: it is
3538  * used when embedding a #ClutterStage into a toolkit with
3539  * another windowing system, like GTK+.
3540  *
3541  * Since: 1.0
3542  */
3543 void
3544 clutter_stage_ensure_redraw (ClutterStage *stage)
3545 {
3546   ClutterMasterClock *master_clock;
3547   ClutterStagePrivate *priv;
3548
3549   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3550
3551   priv = stage->priv;
3552   priv->relayout_pending = TRUE;
3553   priv->redraw_pending = TRUE;
3554
3555   master_clock = _clutter_master_clock_get_default ();
3556   _clutter_master_clock_start_running (master_clock);
3557 }
3558
3559 /**
3560  * clutter_stage_queue_redraw:
3561  * @stage: the #ClutterStage
3562  *
3563  * Queues a redraw for the passed stage.
3564  *
3565  * <note>Applications should call clutter_actor_queue_redraw() and not
3566  * this function.</note>
3567  *
3568  * Since: 0.8
3569  *
3570  * Deprecated: 1.10: Use clutter_actor_queue_redraw() instead.
3571  */
3572 void
3573 clutter_stage_queue_redraw (ClutterStage *stage)
3574 {
3575   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3576
3577   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
3578 }
3579
3580 /**
3581  * clutter_stage_is_default:
3582  * @stage: a #ClutterStage
3583  *
3584  * Checks if @stage is the default stage, or an instance created using
3585  * clutter_stage_new() but internally using the same implementation.
3586  *
3587  * Return value: %TRUE if the passed stage is the default one
3588  *
3589  * Since: 0.8
3590  *
3591  * Deprecated: 1.10: Track the stage pointer inside your application
3592  *   code, or use clutter_actor_get_stage() to retrieve the stage for
3593  *   a given actor.
3594  */
3595 gboolean
3596 clutter_stage_is_default (ClutterStage *stage)
3597 {
3598   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
3599
3600   return stage_is_default (stage);
3601 }
3602
3603 void
3604 _clutter_stage_set_window (ClutterStage       *stage,
3605                            ClutterStageWindow *stage_window)
3606 {
3607   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3608   g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (stage_window));
3609
3610   if (stage->priv->impl != NULL)
3611     g_object_unref (stage->priv->impl);
3612
3613   stage->priv->impl = stage_window;
3614 }
3615
3616 ClutterStageWindow *
3617 _clutter_stage_get_window (ClutterStage *stage)
3618 {
3619   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
3620
3621   return CLUTTER_STAGE_WINDOW (stage->priv->impl);
3622 }
3623
3624 ClutterStageWindow *
3625 _clutter_stage_get_default_window (void)
3626 {
3627   ClutterStageManager *manager = clutter_stage_manager_get_default ();
3628   ClutterStage *stage;
3629
3630   stage = clutter_stage_manager_get_default_stage (manager);
3631   if (stage == NULL)
3632     return NULL;
3633
3634   return _clutter_stage_get_window (stage);
3635 }
3636
3637 /**
3638  * clutter_stage_set_throttle_motion_events:
3639  * @stage: a #ClutterStage
3640  * @throttle: %TRUE to throttle motion events
3641  *
3642  * Sets whether motion events received between redraws should
3643  * be throttled or not. If motion events are throttled, those
3644  * events received by the windowing system between redraws will
3645  * be compressed so that only the last event will be propagated
3646  * to the @stage and its actors.
3647  *
3648  * This function should only be used if you want to have all
3649  * the motion events delivered to your application code.
3650  *
3651  * Since: 1.0
3652  */
3653 void
3654 clutter_stage_set_throttle_motion_events (ClutterStage *stage,
3655                                           gboolean      throttle)
3656 {
3657   ClutterStagePrivate *priv;
3658
3659   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3660
3661   priv = stage->priv;
3662
3663   if (priv->throttle_motion_events != throttle)
3664     priv->throttle_motion_events = throttle;
3665 }
3666
3667 /**
3668  * clutter_stage_get_throttle_motion_events:
3669  * @stage: a #ClutterStage
3670  *
3671  * Retrieves the value set with clutter_stage_set_throttle_motion_events()
3672  *
3673  * Return value: %TRUE if the motion events are being throttled,
3674  *   and %FALSE otherwise
3675  *
3676  * Since: 1.0
3677  */
3678 gboolean
3679 clutter_stage_get_throttle_motion_events (ClutterStage *stage)
3680 {
3681   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
3682
3683   return stage->priv->throttle_motion_events;
3684 }
3685
3686 /**
3687  * clutter_stage_set_use_alpha:
3688  * @stage: a #ClutterStage
3689  * @use_alpha: whether the stage should honour the opacity or the
3690  *   alpha channel of the stage color
3691  *
3692  * Sets whether the @stage should honour the #ClutterActor:opacity and
3693  * the alpha channel of the #ClutterStage:color
3694  *
3695  * Since: 1.2
3696  */
3697 void
3698 clutter_stage_set_use_alpha (ClutterStage *stage,
3699                              gboolean      use_alpha)
3700 {
3701   ClutterStagePrivate *priv;
3702
3703   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3704
3705   priv = stage->priv;
3706
3707   if (priv->use_alpha != use_alpha)
3708     {
3709       priv->use_alpha = use_alpha;
3710
3711       clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
3712
3713       g_object_notify (G_OBJECT (stage), "use-alpha");
3714     }
3715 }
3716
3717 /**
3718  * clutter_stage_get_use_alpha:
3719  * @stage: a #ClutterStage
3720  *
3721  * Retrieves the value set using clutter_stage_set_use_alpha()
3722  *
3723  * Return value: %TRUE if the stage should honour the opacity and the
3724  *   alpha channel of the stage color
3725  *
3726  * Since: 1.2
3727  */
3728 gboolean
3729 clutter_stage_get_use_alpha (ClutterStage *stage)
3730 {
3731   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
3732
3733   return stage->priv->use_alpha;
3734 }
3735
3736 /**
3737  * clutter_stage_set_minimum_size:
3738  * @stage: a #ClutterStage
3739  * @width: width, in pixels
3740  * @height: height, in pixels
3741  *
3742  * Sets the minimum size for a stage window, if the default backend
3743  * uses #ClutterStage inside a window
3744  *
3745  * This is a convenience function, and it is equivalent to setting the
3746  * #ClutterActor:min-width and #ClutterActor:min-height on @stage
3747  *
3748  * If the current size of @stage is smaller than the minimum size, the
3749  * @stage will be resized to the new @width and @height
3750  *
3751  * This function has no effect if @stage is fullscreen
3752  *
3753  * Since: 1.2
3754  */
3755 void
3756 clutter_stage_set_minimum_size (ClutterStage *stage,
3757                                 guint         width,
3758                                 guint         height)
3759 {
3760   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3761   g_return_if_fail ((width > 0) && (height > 0));
3762
3763   g_object_set (G_OBJECT (stage),
3764                 "min-width", (gfloat) width,
3765                 "min-height", (gfloat )height,
3766                 NULL);
3767 }
3768
3769 /**
3770  * clutter_stage_get_minimum_size:
3771  * @stage: a #ClutterStage
3772  * @width: (out): return location for the minimum width, in pixels,
3773  *   or %NULL
3774  * @height: (out): return location for the minimum height, in pixels,
3775  *   or %NULL
3776  *
3777  * Retrieves the minimum size for a stage window as set using
3778  * clutter_stage_set_minimum_size().
3779  *
3780  * The returned size may not correspond to the actual minimum size and
3781  * it is specific to the #ClutterStage implementation inside the
3782  * Clutter backend
3783  *
3784  * Since: 1.2
3785  */
3786 void
3787 clutter_stage_get_minimum_size (ClutterStage *stage,
3788                                 guint        *width_p,
3789                                 guint        *height_p)
3790 {
3791   gfloat width, height;
3792   gboolean width_set, height_set;
3793
3794   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3795
3796   g_object_get (G_OBJECT (stage),
3797                 "min-width", &width,
3798                 "min-width-set", &width_set,
3799                 "min-height", &height,
3800                 "min-height-set", &height_set,
3801                 NULL);
3802
3803   /* if not width or height have been set, then the Stage
3804    * minimum size is defined to be 1x1
3805    */
3806   if (!width_set)
3807     width = 1;
3808
3809   if (!height_set)
3810     height = 1;
3811
3812   if (width_p)
3813     *width_p = (guint) width;
3814
3815   if (height_p)
3816     *height_p = (guint) height;
3817 }
3818
3819 /* Returns the number of swap buffers pending completion for the stage */
3820 int
3821 _clutter_stage_get_pending_swaps (ClutterStage *stage)
3822 {
3823   ClutterStageWindow *stage_window;
3824
3825   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
3826     return 0;
3827
3828   stage_window = _clutter_stage_get_window (stage);
3829   if (stage_window == NULL)
3830     return 0;
3831
3832   return _clutter_stage_window_get_pending_swaps (stage_window);
3833 }
3834
3835 /**
3836  * clutter_stage_set_no_clear_hint:
3837  * @stage: a #ClutterStage
3838  * @no_clear: %TRUE if the @stage should not clear itself on every
3839  *   repaint cycle
3840  *
3841  * Sets whether the @stage should clear itself at the beginning
3842  * of each paint cycle or not.
3843  *
3844  * Clearing the #ClutterStage can be a costly operation, especially
3845  * if the stage is always covered - for instance, in a full-screen
3846  * video player or in a game with a background texture.
3847  *
3848  * <note><para>This setting is a hint; Clutter might discard this
3849  * hint depending on its internal state.</para></note>
3850  *
3851  * <warning><para>If parts of the stage are visible and you disable
3852  * clearing you might end up with visual artifacts while painting the
3853  * contents of the stage.</para></warning>
3854  *
3855  * Since: 1.4
3856  */
3857 void
3858 clutter_stage_set_no_clear_hint (ClutterStage *stage,
3859                                  gboolean      no_clear)
3860 {
3861   ClutterStagePrivate *priv;
3862   ClutterStageHint new_hints;
3863
3864   g_return_if_fail (CLUTTER_IS_STAGE (stage));
3865
3866   priv = stage->priv;
3867   new_hints = priv->stage_hints;
3868
3869   if (no_clear)
3870     new_hints |= CLUTTER_STAGE_NO_CLEAR_ON_PAINT;
3871   else
3872     new_hints &= ~CLUTTER_STAGE_NO_CLEAR_ON_PAINT;
3873
3874   if (priv->stage_hints == new_hints)
3875     return;
3876
3877   priv->stage_hints = new_hints;
3878
3879   g_object_notify (G_OBJECT (stage), "no-clear-hint");
3880 }
3881
3882 /**
3883  * clutter_stage_get_no_clear_hint:
3884  * @stage: a #ClutterStage
3885  *
3886  * Retrieves the hint set with clutter_stage_set_no_clear_hint()
3887  *
3888  * Return value: %TRUE if the stage should not clear itself on every paint
3889  *   cycle, and %FALSE otherwise
3890  *
3891  * Since: 1.4
3892  */
3893 gboolean
3894 clutter_stage_get_no_clear_hint (ClutterStage *stage)
3895 {
3896   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
3897
3898   return (stage->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0;
3899 }
3900
3901 ClutterPaintVolume *
3902 _clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
3903 {
3904   GArray *paint_volume_stack = stage->priv->paint_volume_stack;
3905
3906   g_array_set_size (paint_volume_stack,
3907                     paint_volume_stack->len+1);
3908
3909   return &g_array_index (paint_volume_stack,
3910                          ClutterPaintVolume,
3911                          paint_volume_stack->len - 1);
3912 }
3913
3914 void
3915 _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage)
3916 {
3917   GArray *paint_volume_stack = stage->priv->paint_volume_stack;
3918   int i;
3919
3920   for (i = 0; i < paint_volume_stack->len; i++)
3921     {
3922       ClutterPaintVolume *pv =
3923         &g_array_index (paint_volume_stack, ClutterPaintVolume, i);
3924       clutter_paint_volume_free (pv);
3925     }
3926
3927   g_array_set_size (paint_volume_stack, 0);
3928 }
3929
3930 /* The is an out-of-band paramater available while painting that
3931  * can be used to cull actors. */
3932 const ClutterPlane *
3933 _clutter_stage_get_clip (ClutterStage *stage)
3934 {
3935   return stage->priv->current_clip_planes;
3936 }
3937
3938 /* When an actor queues a redraw we add it to a list on the stage that
3939  * gets processed once all updates to the stage have been finished.
3940  *
3941  * This deferred approach to processing queue_redraw requests means
3942  * that we can avoid redundant transformations of clip volumes if
3943  * something later triggers a full stage redraw anyway. It also means
3944  * we can be more sure that all the referenced actors will have valid
3945  * allocations improving the chance that we can determine the actors
3946  * paint volume so we can clip the redraw request even if the user
3947  * didn't explicitly do so.
3948  */
3949 ClutterStageQueueRedrawEntry *
3950 _clutter_stage_queue_actor_redraw (ClutterStage *stage,
3951                                    ClutterStageQueueRedrawEntry *entry,
3952                                    ClutterActor *actor,
3953                                    ClutterPaintVolume *clip)
3954 {
3955   ClutterStagePrivate *priv = stage->priv;
3956
3957   CLUTTER_NOTE (CLIPPING, "stage_queue_actor_redraw (actor=%s, clip=%p): ",
3958                 _clutter_actor_get_debug_name (actor), clip);
3959
3960   if (!priv->redraw_pending)
3961     {
3962       ClutterMasterClock *master_clock;
3963
3964       CLUTTER_NOTE (PAINT, "First redraw request");
3965
3966       priv->redraw_pending = TRUE;
3967
3968       master_clock = _clutter_master_clock_get_default ();
3969       _clutter_master_clock_start_running (master_clock);
3970     }
3971 #ifdef CLUTTER_ENABLE_DEBUG
3972   else
3973     {
3974       CLUTTER_NOTE (PAINT, "Redraw request number %lu",
3975                     priv->redraw_count + 1);
3976
3977       priv->redraw_count += 1;
3978     }
3979 #endif /* CLUTTER_ENABLE_DEBUG */
3980
3981   /* We have an optimization in _clutter_stage_do_pick to detect when
3982    * the scene is static so we can cache a full, un-clipped pick
3983    * buffer to avoid continuous pick renders.
3984    *
3985    * Currently the assumption is that actors queue a redraw when some
3986    * state changes that affects painting *or* picking so we can use
3987    * this point to invalidate any currently cached pick buffer.
3988    */
3989   _clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
3990
3991   if (entry)
3992     {
3993       /* Ignore all requests to queue a redraw for an actor if a full
3994        * (non-clipped) redraw of the actor has already been queued. */
3995       if (!entry->has_clip)
3996         {
3997           CLUTTER_NOTE (CLIPPING, "Bail from stage_queue_actor_redraw (%s): "
3998                         "Unclipped redraw of actor already queued",
3999                         _clutter_actor_get_debug_name (actor));
4000           return entry;
4001         }
4002
4003       /* If queuing a clipped redraw and a clipped redraw has
4004        * previously been queued for this actor then combine the latest
4005        * clip together with the existing clip */
4006       if (clip)
4007         clutter_paint_volume_union (&entry->clip, clip);
4008       else
4009         {
4010           clutter_paint_volume_free (&entry->clip);
4011           entry->has_clip = FALSE;
4012         }
4013       return entry;
4014     }
4015   else
4016     {
4017       entry = g_slice_new (ClutterStageQueueRedrawEntry);
4018       entry->actor = g_object_ref (actor);
4019
4020       if (clip)
4021         {
4022           entry->has_clip = TRUE;
4023           _clutter_paint_volume_init_static (&entry->clip, actor);
4024           _clutter_paint_volume_set_from_volume (&entry->clip, clip);
4025         }
4026       else
4027         entry->has_clip = FALSE;
4028
4029       stage->priv->pending_queue_redraws =
4030         g_list_prepend (stage->priv->pending_queue_redraws, entry);
4031
4032       return entry;
4033     }
4034 }
4035
4036 static void
4037 free_queue_redraw_entry (ClutterStageQueueRedrawEntry *entry)
4038 {
4039   if (entry->actor)
4040     g_object_unref (entry->actor);
4041   if (entry->has_clip)
4042     clutter_paint_volume_free (&entry->clip);
4043   g_slice_free (ClutterStageQueueRedrawEntry, entry);
4044 }
4045
4046 void
4047 _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry)
4048 {
4049   if (entry == NULL)
4050     return;
4051
4052   if (entry->actor != NULL)
4053     {
4054       g_object_unref (entry->actor);
4055       entry->actor = NULL;
4056     }
4057
4058   if (entry->has_clip)
4059     {
4060       clutter_paint_volume_free (&entry->clip);
4061       entry->has_clip = FALSE;
4062     }
4063 }
4064
4065 static void
4066 _clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
4067 {
4068   /* Note: we have to repeat until the pending_queue_redraws list is
4069    * empty because actors are allowed to queue redraws in response to
4070    * the queue-redraw signal. For example Clone actors or
4071    * texture_new_from_actor actors will have to queue a redraw if
4072    * their source queues a redraw.
4073    */
4074   while (stage->priv->pending_queue_redraws)
4075     {
4076       GList *l;
4077       /* XXX: we need to allow stage->priv->pending_queue_redraws to
4078        * be updated while we process the current entries in the list
4079        * so we steal the list pointer and then reset it to an empty
4080        * list before processing... */
4081       GList *stolen_list = stage->priv->pending_queue_redraws;
4082       stage->priv->pending_queue_redraws = NULL;
4083
4084       for (l = stolen_list; l; l = l->next)
4085         {
4086           ClutterStageQueueRedrawEntry *entry = l->data;
4087           ClutterPaintVolume *clip;
4088
4089           /* NB: Entries may be invalidated if the actor gets destroyed */
4090           if (G_LIKELY (entry->actor != NULL))
4091             {
4092               clip = entry->has_clip ? &entry->clip : NULL;
4093
4094               _clutter_actor_finish_queue_redraw (entry->actor, clip);
4095             }
4096
4097           free_queue_redraw_entry (entry);
4098         }
4099       g_list_free (stolen_list);
4100     }
4101 }
4102
4103 /**
4104  * clutter_stage_set_accept_focus:
4105  * @stage: a #ClutterStage
4106  * @accept_focus: %TRUE to accept focus on show
4107  *
4108  * Sets whether the @stage should accept the key focus when shown.
4109  *
4110  * This function should be called before showing @stage using
4111  * clutter_actor_show().
4112  *
4113  * Since: 1.6
4114  */
4115 void
4116 clutter_stage_set_accept_focus (ClutterStage *stage,
4117                                 gboolean      accept_focus)
4118 {
4119   ClutterStagePrivate *priv;
4120
4121   g_return_if_fail (CLUTTER_IS_STAGE (stage));
4122
4123   accept_focus = !!accept_focus;
4124
4125   priv = stage->priv;
4126
4127   if (priv->accept_focus != accept_focus)
4128     {
4129       _clutter_stage_window_set_accept_focus (priv->impl, accept_focus);
4130       g_object_notify (G_OBJECT (stage), "accept-focus");
4131     }
4132 }
4133
4134 /**
4135  * clutter_stage_get_accept_focus:
4136  * @stage: a #ClutterStage
4137  *
4138  * Retrieves the value set with clutter_stage_set_accept_focus().
4139  *
4140  * Return value: %TRUE if the #ClutterStage should accept focus, and %FALSE
4141  *   otherwise
4142  *
4143  * Since: 1.6
4144  */
4145 gboolean
4146 clutter_stage_get_accept_focus (ClutterStage *stage)
4147 {
4148   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), TRUE);
4149
4150   return stage->priv->accept_focus;
4151 }
4152
4153 void
4154 _clutter_stage_add_device (ClutterStage       *stage,
4155                            ClutterInputDevice *device)
4156 {
4157   ClutterStagePrivate *priv = stage->priv;
4158
4159   if (g_hash_table_lookup (priv->devices, device) != NULL)
4160     return;
4161
4162   g_hash_table_insert (priv->devices, device, GINT_TO_POINTER (1));
4163   _clutter_input_device_set_stage (device, stage);
4164 }
4165
4166 void
4167 _clutter_stage_remove_device (ClutterStage       *stage,
4168                               ClutterInputDevice *device)
4169 {
4170   ClutterStagePrivate *priv = stage->priv;
4171
4172   _clutter_input_device_set_stage (device, NULL);
4173   g_hash_table_remove (priv->devices, device);
4174 }
4175
4176 gboolean
4177 _clutter_stage_has_device (ClutterStage       *stage,
4178                            ClutterInputDevice *device)
4179 {
4180   ClutterStagePrivate *priv = stage->priv;
4181
4182   return g_hash_table_lookup (priv->devices, device) != NULL;
4183 }
4184
4185 /**
4186  * clutter_stage_set_motion_events_enabled:
4187  * @stage: a #ClutterStage
4188  * @enabled: %TRUE to enable the motion events delivery, and %FALSE
4189  *   otherwise
4190  *
4191  * Sets whether per-actor motion events (and relative crossing
4192  * events) should be disabled or not.
4193  *
4194  * The default is %TRUE.
4195  *
4196  * If @enable is %FALSE the following events will not be delivered
4197  * to the actors children of @stage.
4198  *
4199  * <itemizedlist>
4200  *   <listitem><para>#ClutterActor::motion-event</para></listitem>
4201  *   <listitem><para>#ClutterActor::enter-event</para></listitem>
4202  *   <listitem><para>#ClutterActor::leave-event</para></listitem>
4203  * </itemizedlist>
4204  *
4205  * The events will still be delivered to the #ClutterStage.
4206  *
4207  * The main side effect of this function is that disabling the motion
4208  * events will disable picking to detect the #ClutterActor underneath
4209  * the pointer for each motion event. This is useful, for instance,
4210  * when dragging a #ClutterActor across the @stage: the actor underneath
4211  * the pointer is not going to change, so it's meaningless to perform
4212  * a pick.
4213  *
4214  * Since: 1.8
4215  */
4216 void
4217 clutter_stage_set_motion_events_enabled (ClutterStage *stage,
4218                                          gboolean      enabled)
4219 {
4220   ClutterStagePrivate *priv;
4221
4222   g_return_if_fail (CLUTTER_IS_STAGE (stage));
4223
4224   priv = stage->priv;
4225
4226   enabled = !!enabled;
4227
4228   if (priv->motion_events_enabled != enabled)
4229     priv->motion_events_enabled = enabled;
4230 }
4231
4232 /**
4233  * clutter_stage_get_motion_events_enabled:
4234  * @stage: a #ClutterStage
4235  *
4236  * Retrieves the value set using clutter_stage_set_motion_events_enabled().
4237  *
4238  * Return value: %TRUE if the per-actor motion event delivery is enabled
4239  *   and %FALSE otherwise
4240  *
4241  * Since: 1.8
4242  */
4243 gboolean
4244 clutter_stage_get_motion_events_enabled (ClutterStage *stage)
4245 {
4246   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
4247
4248   return stage->priv->motion_events_enabled;
4249 }
4250
4251 /* NB: The presumption shouldn't be that a stage can't be comprised
4252  * of multiple internal framebuffers, so instead of simply naming
4253  * this function _clutter_stage_get_framebuffer(), the "active"
4254  * infix is intended to clarify that it gets the framebuffer that
4255  * is currently in use/being painted.
4256  */
4257 CoglFramebuffer *
4258 _clutter_stage_get_active_framebuffer (ClutterStage *stage)
4259 {
4260   return stage->priv->active_framebuffer;
4261 }
4262
4263 gint32
4264 _clutter_stage_acquire_pick_id (ClutterStage *stage,
4265                                 ClutterActor *actor)
4266 {
4267   ClutterStagePrivate *priv = stage->priv;
4268
4269   g_assert (priv->pick_id_pool != NULL);
4270
4271   return _clutter_id_pool_add (priv->pick_id_pool, actor);
4272 }
4273
4274 void
4275 _clutter_stage_release_pick_id (ClutterStage *stage,
4276                                 gint32        pick_id)
4277 {
4278   ClutterStagePrivate *priv = stage->priv;
4279
4280   g_assert (priv->pick_id_pool != NULL);
4281
4282   _clutter_id_pool_remove (priv->pick_id_pool, pick_id);
4283 }
4284
4285 ClutterActor *
4286 _clutter_stage_get_actor_by_pick_id (ClutterStage *stage,
4287                                      gint32        pick_id)
4288 {
4289   ClutterStagePrivate *priv = stage->priv;
4290
4291   g_assert (priv->pick_id_pool != NULL);
4292
4293   return _clutter_id_pool_lookup (priv->pick_id_pool, pick_id);
4294 }
4295
4296 void
4297 _clutter_stage_add_drag_actor (ClutterStage       *stage,
4298                                ClutterInputDevice *device,
4299                                ClutterActor       *actor)
4300 {
4301   GHashTable *drag_actors;
4302
4303   drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_drag_actors");
4304   if (drag_actors == NULL)
4305     {
4306       drag_actors = g_hash_table_new (NULL, NULL);
4307       g_object_set_data_full (G_OBJECT (stage), "__clutter_stage_drag_actors",
4308                               drag_actors,
4309                               (GDestroyNotify) g_hash_table_destroy);
4310     }
4311
4312   g_hash_table_replace (drag_actors, device, actor);
4313 }
4314
4315 ClutterActor *
4316 _clutter_stage_get_drag_actor (ClutterStage       *stage,
4317                                ClutterInputDevice *device)
4318 {
4319   GHashTable *drag_actors;
4320
4321   drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_drag_actors");
4322   if (drag_actors == NULL)
4323     return NULL;
4324
4325   return g_hash_table_lookup (drag_actors, device);
4326 }
4327
4328 void
4329 _clutter_stage_remove_drag_actor (ClutterStage       *stage,
4330                                   ClutterInputDevice *device)
4331 {
4332   GHashTable *drag_actors;
4333
4334   drag_actors = g_object_get_data (G_OBJECT (stage), "__clutter_stage_drag_actors");
4335   if (drag_actors == NULL)
4336     return;
4337
4338   g_hash_table_remove (drag_actors, device);
4339
4340   if (g_hash_table_size (drag_actors) == 0)
4341     g_object_set_data (G_OBJECT (stage), "__clutter_stage_drag_actors", NULL);
4342 }
4343
4344 /*< private >
4345  * _clutter_stage_get_state:
4346  * @stage: a #ClutterStage
4347  *
4348  * Retrieves the current #ClutterStageState flags associated to the @stage.
4349  *
4350  * Return value: a bitwise OR of #ClutterStageState flags
4351  */
4352 ClutterStageState
4353 _clutter_stage_get_state (ClutterStage *stage)
4354 {
4355   return stage->priv->current_state;
4356 }
4357
4358 /*< private >
4359  * _clutter_stage_is_activated:
4360  * @stage: a #ClutterStage
4361  *
4362  * Checks whether the @stage state includes %CLUTTER_STAGE_STATE_ACTIVATED.
4363  *
4364  * Return value: %TRUE if the @stage is active
4365  */
4366 gboolean
4367 _clutter_stage_is_activated (ClutterStage *stage)
4368 {
4369   return (stage->priv->current_state & CLUTTER_STAGE_STATE_ACTIVATED) != 0;
4370 }
4371
4372 /*< private >
4373  * _clutter_stage_is_fullscreen:
4374  * @stage: a #ClutterStage
4375  *
4376  * Checks whether the @stage state includes %CLUTTER_STAGE_STATE_FULLSCREEN.
4377  *
4378  * Return value: %TRUE if the @stage is fullscreen
4379  */
4380 gboolean
4381 _clutter_stage_is_fullscreen (ClutterStage *stage)
4382 {
4383   return (stage->priv->current_state & CLUTTER_STAGE_STATE_FULLSCREEN) != 0;
4384 }
4385
4386 /*< private >
4387  * _clutter_stage_update_state:
4388  * @stage: a #ClutterStage
4389  * @unset_flags: flags to unset
4390  * @set_flags: flags to set
4391  *
4392  * Updates the state of @stage, by unsetting the @unset_flags and setting
4393  * the @set_flags.
4394  *
4395  * If the stage state has been changed, this function will queue a
4396  * #ClutterEvent of type %CLUTTER_STAGE_STATE.
4397  *
4398  * Return value: %TRUE if the state was updated, and %FALSE otherwise
4399  */
4400 gboolean
4401 _clutter_stage_update_state (ClutterStage      *stage,
4402                              ClutterStageState  unset_flags,
4403                              ClutterStageState  set_flags)
4404 {
4405   ClutterStageState new_state;
4406   ClutterEvent *event;
4407
4408   new_state = stage->priv->current_state;
4409   new_state |= set_flags;
4410   new_state &= ~unset_flags;
4411
4412   if (new_state == stage->priv->current_state)
4413     return FALSE;
4414
4415   event = clutter_event_new (CLUTTER_STAGE_STATE);
4416   clutter_event_set_stage (event, stage);
4417
4418   event->stage_state.new_state = new_state;
4419   event->stage_state.changed_mask = new_state ^ stage->priv->current_state;
4420
4421   stage->priv->current_state = new_state;
4422
4423   _clutter_event_push (event, FALSE);
4424
4425   return TRUE;
4426 }