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