actor: Add a default handler for ::destroy
[profile/ivi/clutter.git] / clutter / clutter-actor.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, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326
327 #include "clutter-actor-private.h"
328
329 #include "clutter-action.h"
330 #include "clutter-actor-meta-private.h"
331 #include "clutter-animatable.h"
332 #include "clutter-color-static.h"
333 #include "clutter-color.h"
334 #include "clutter-constraint.h"
335 #include "clutter-container.h"
336 #include "clutter-debug.h"
337 #include "clutter-effect-private.h"
338 #include "clutter-enum-types.h"
339 #include "clutter-fixed-layout.h"
340 #include "clutter-main.h"
341 #include "clutter-marshal.h"
342 #include "clutter-flatten-effect.h"
343 #include "clutter-paint-volume-private.h"
344 #include "clutter-private.h"
345 #include "clutter-profile.h"
346 #include "clutter-scriptable.h"
347 #include "clutter-script-private.h"
348 #include "clutter-stage-private.h"
349 #include "clutter-units.h"
350
351 #include "deprecated/clutter-behaviour.h"
352 #include "deprecated/clutter-container.h"
353
354 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
355 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
356
357 /* Internal enum used to control mapped state update.  This is a hint
358  * which indicates when to do something other than just enforce
359  * invariants.
360  */
361 typedef enum {
362   MAP_STATE_CHECK,           /* just enforce invariants. */
363   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
364                               * used when about to unparent.
365                               */
366   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
367                               * used to set mapped on toplevels.
368                               */
369   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
370                               * used just before unmapping parent.
371                               */
372 } MapStateChange;
373
374 /* 3 entries should be a good compromise, few layout managers
375  * will ask for 3 different preferred size in each allocation cycle */
376 #define N_CACHED_SIZE_REQUESTS 3
377
378 struct _ClutterActorPrivate
379 {
380   /* request mode */
381   ClutterRequestMode request_mode;
382
383   /* our cached size requests for different width / height */
384   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
385   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
386
387   /* An age of 0 means the entry is not set */
388   guint cached_height_age;
389   guint cached_width_age;
390
391   /* the bounding box of the actor, relative to the parent's
392    * allocation
393    */
394   ClutterActorBox allocation;
395   ClutterAllocationFlags allocation_flags;
396
397   /* depth */
398   gfloat z;
399
400   /* clip, in actor coordinates */
401   cairo_rectangle_t clip;
402
403   /* the cached transformation matrix; see apply_transform() */
404   CoglMatrix transform;
405
406   guint8 opacity;
407   gint opacity_override;
408
409   ClutterOffscreenRedirect offscreen_redirect;
410
411   /* This is an internal effect used to implement the
412      offscreen-redirect property */
413   ClutterEffect *flatten_effect;
414
415   /* scene graph */
416   ClutterActor *parent;
417   ClutterActor *prev_sibling;
418   ClutterActor *next_sibling;
419   ClutterActor *first_child;
420   ClutterActor *last_child;
421
422   gint n_children;
423
424   /* tracks whenever the children of an actor are changed; the
425    * age is incremented by 1 whenever an actor is added or
426    * removed. the age is not incremented when the first or the
427    * last child pointers are changed, or when grandchildren of
428    * an actor are changed.
429    */
430   gint age;
431
432   gchar *name; /* a non-unique name, used for debugging */
433   guint32 id; /* unique id, used for backward compatibility */
434
435   gint32 pick_id; /* per-stage unique id, used for picking */
436
437   /* a back-pointer to the Pango context that we can use
438    * to create pre-configured PangoLayout
439    */
440   PangoContext *pango_context;
441
442   /* the text direction configured for this child - either by
443    * application code, or by the actor's parent
444    */
445   ClutterTextDirection text_direction;
446
447   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
448   gint internal_child;
449
450   /* meta classes */
451   ClutterMetaGroup *actions;
452   ClutterMetaGroup *constraints;
453   ClutterMetaGroup *effects;
454
455   /* delegate object used to allocate the children of this actor */
456   ClutterLayoutManager *layout_manager;
457
458   /* used when painting, to update the paint volume */
459   ClutterEffect *current_effect;
460
461   /* This is used to store an effect which needs to be redrawn. A
462      redraw can be queued to start from a particular effect. This is
463      used by parametrised effects that can cache an image of the
464      actor. If a parameter of the effect changes then it only needs to
465      redraw the cached image, not the actual actor. The pointer is
466      only valid if is_dirty == TRUE. If the pointer is NULL then the
467      whole actor is dirty. */
468   ClutterEffect *effect_to_redraw;
469
470   /* This is used when painting effects to implement the
471      clutter_actor_continue_paint() function. It points to the node in
472      the list of effects that is next in the chain */
473   const GList *next_effect_to_paint;
474
475   ClutterPaintVolume paint_volume;
476
477   /* NB: This volume isn't relative to this actor, it is in eye
478    * coordinates so that it can remain valid after the actor changes.
479    */
480   ClutterPaintVolume last_paint_volume;
481
482   ClutterStageQueueRedrawEntry *queue_redraw_entry;
483
484   ClutterColor bg_color;
485
486   /* bitfields */
487
488   /* fixed position and sizes */
489   guint position_set                : 1;
490   guint min_width_set               : 1;
491   guint min_height_set              : 1;
492   guint natural_width_set           : 1;
493   guint natural_height_set          : 1;
494   /* cached request is invalid (implies allocation is too) */
495   guint needs_width_request         : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_height_request        : 1;
498   /* cached allocation is invalid (request has changed, probably) */
499   guint needs_allocation            : 1;
500   guint show_on_set_parent          : 1;
501   guint has_clip                    : 1;
502   guint clip_to_allocation          : 1;
503   guint enable_model_view_transform : 1;
504   guint enable_paint_unmapped       : 1;
505   guint has_pointer                 : 1;
506   guint propagated_one_redraw       : 1;
507   guint paint_volume_valid          : 1;
508   guint last_paint_volume_valid     : 1;
509   guint in_clone_paint              : 1;
510   guint transform_valid             : 1;
511   /* This is TRUE if anything has queued a redraw since we were last
512      painted. In this case effect_to_redraw will point to an effect
513      the redraw was queued from or it will be NULL if the redraw was
514      queued without an effect. */
515   guint is_dirty                    : 1;
516   guint bg_color_set                : 1;
517 };
518
519 enum
520 {
521   PROP_0,
522
523   PROP_NAME,
524
525   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
526    * when set they force a size request, when gotten they
527    * get the allocation if the allocation is valid, and the
528    * request otherwise
529    */
530   PROP_X,
531   PROP_Y,
532   PROP_WIDTH,
533   PROP_HEIGHT,
534
535   /* Then the rest of these size-related properties are the "actual"
536    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
537    */
538   PROP_FIXED_X,
539   PROP_FIXED_Y,
540
541   PROP_FIXED_POSITION_SET,
542
543   PROP_MIN_WIDTH,
544   PROP_MIN_WIDTH_SET,
545
546   PROP_MIN_HEIGHT,
547   PROP_MIN_HEIGHT_SET,
548
549   PROP_NATURAL_WIDTH,
550   PROP_NATURAL_WIDTH_SET,
551
552   PROP_NATURAL_HEIGHT,
553   PROP_NATURAL_HEIGHT_SET,
554
555   PROP_REQUEST_MODE,
556
557   /* Allocation properties are read-only */
558   PROP_ALLOCATION,
559
560   PROP_DEPTH,
561
562   PROP_CLIP,
563   PROP_HAS_CLIP,
564   PROP_CLIP_TO_ALLOCATION,
565
566   PROP_OPACITY,
567
568   PROP_OFFSCREEN_REDIRECT,
569
570   PROP_VISIBLE,
571   PROP_MAPPED,
572   PROP_REALIZED,
573   PROP_REACTIVE,
574
575   PROP_SCALE_X,
576   PROP_SCALE_Y,
577   PROP_SCALE_CENTER_X,
578   PROP_SCALE_CENTER_Y,
579   PROP_SCALE_GRAVITY,
580
581   PROP_ROTATION_ANGLE_X,
582   PROP_ROTATION_ANGLE_Y,
583   PROP_ROTATION_ANGLE_Z,
584   PROP_ROTATION_CENTER_X,
585   PROP_ROTATION_CENTER_Y,
586   PROP_ROTATION_CENTER_Z,
587   /* This property only makes sense for the z rotation because the
588      others would depend on the actor having a size along the
589      z-axis */
590   PROP_ROTATION_CENTER_Z_GRAVITY,
591
592   PROP_ANCHOR_X,
593   PROP_ANCHOR_Y,
594   PROP_ANCHOR_GRAVITY,
595
596   PROP_SHOW_ON_SET_PARENT,
597
598   PROP_TEXT_DIRECTION,
599   PROP_HAS_POINTER,
600
601   PROP_ACTIONS,
602   PROP_CONSTRAINTS,
603   PROP_EFFECT,
604
605   PROP_LAYOUT_MANAGER,
606
607   PROP_X_ALIGN,
608   PROP_Y_ALIGN,
609   PROP_MARGIN_TOP,
610   PROP_MARGIN_BOTTOM,
611   PROP_MARGIN_LEFT,
612   PROP_MARGIN_RIGHT,
613
614   PROP_BACKGROUND_COLOR,
615   PROP_BACKGROUND_COLOR_SET,
616
617   PROP_FIRST_CHILD,
618   PROP_LAST_CHILD,
619
620   PROP_LAST
621 };
622
623 static GParamSpec *obj_props[PROP_LAST];
624
625 enum
626 {
627   SHOW,
628   HIDE,
629   DESTROY,
630   PARENT_SET,
631   KEY_FOCUS_IN,
632   KEY_FOCUS_OUT,
633   PAINT,
634   PICK,
635   REALIZE,
636   UNREALIZE,
637   QUEUE_REDRAW,
638   QUEUE_RELAYOUT,
639   EVENT,
640   CAPTURED_EVENT,
641   BUTTON_PRESS_EVENT,
642   BUTTON_RELEASE_EVENT,
643   SCROLL_EVENT,
644   KEY_PRESS_EVENT,
645   KEY_RELEASE_EVENT,
646   MOTION_EVENT,
647   ENTER_EVENT,
648   LEAVE_EVENT,
649   ALLOCATION_CHANGED,
650
651   LAST_SIGNAL
652 };
653
654 static guint actor_signals[LAST_SIGNAL] = { 0, };
655
656 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
657 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
658 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
659 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
660
661 /* These setters are all static for now, maybe they should be in the
662  * public API, but they are perhaps obscure enough to leave only as
663  * properties
664  */
665 static void clutter_actor_set_min_width          (ClutterActor *self,
666                                                   gfloat        min_width);
667 static void clutter_actor_set_min_height         (ClutterActor *self,
668                                                   gfloat        min_height);
669 static void clutter_actor_set_natural_width      (ClutterActor *self,
670                                                   gfloat        natural_width);
671 static void clutter_actor_set_natural_height     (ClutterActor *self,
672                                                   gfloat        natural_height);
673 static void clutter_actor_set_min_width_set      (ClutterActor *self,
674                                                   gboolean      use_min_width);
675 static void clutter_actor_set_min_height_set     (ClutterActor *self,
676                                                   gboolean      use_min_height);
677 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
678                                                   gboolean  use_natural_width);
679 static void clutter_actor_set_natural_height_set (ClutterActor *self,
680                                                   gboolean  use_natural_height);
681 static void clutter_actor_update_map_state       (ClutterActor  *self,
682                                                   MapStateChange change);
683 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
684
685 /* Helper routines for managing anchor coords */
686 static void clutter_anchor_coord_get_units (ClutterActor      *self,
687                                             const AnchorCoord *coord,
688                                             gfloat            *x,
689                                             gfloat            *y,
690                                             gfloat            *z);
691 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
692                                             gfloat             x,
693                                             gfloat             y,
694                                             gfloat             z);
695
696 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
697 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
698                                                         ClutterGravity     gravity);
699
700 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
701
702 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
703
704 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
705                                                                ClutterActor *ancestor,
706                                                                CoglMatrix *matrix);
707
708 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
709
710 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
711
712 static void on_layout_manager_changed (ClutterLayoutManager *manager,
713                                        ClutterActor         *self);
714
715 /* Helper macro which translates by the anchor coord, applies the
716    given transformation and then translates back */
717 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
718   gfloat _tx, _ty, _tz;                                                \
719   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
720   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
721   { _transform; }                                                      \
722   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
723
724 static GQuark quark_shader_data = 0;
725 static GQuark quark_actor_layout_info = 0;
726 static GQuark quark_actor_transform_info = 0;
727
728 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
729                          clutter_actor,
730                          G_TYPE_INITIALLY_UNOWNED,
731                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
732                                                 clutter_container_iface_init)
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
734                                                 clutter_scriptable_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
736                                                 clutter_animatable_iface_init)
737                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
738                                                 atk_implementor_iface_init));
739
740 /*< private >
741  * clutter_actor_get_debug_name:
742  * @actor: a #ClutterActor
743  *
744  * Retrieves a printable name of @actor for debugging messages
745  *
746  * Return value: a string with a printable name
747  */
748 const gchar *
749 _clutter_actor_get_debug_name (ClutterActor *actor)
750 {
751   return actor->priv->name != NULL ? actor->priv->name
752                                    : G_OBJECT_TYPE_NAME (actor);
753 }
754
755 #ifdef CLUTTER_ENABLE_DEBUG
756 /* XXX - this is for debugging only, remove once working (or leave
757  * in only in some debug mode). Should leave it for a little while
758  * until we're confident in the new map/realize/visible handling.
759  */
760 static inline void
761 clutter_actor_verify_map_state (ClutterActor *self)
762 {
763   ClutterActorPrivate *priv = self->priv;
764
765   if (CLUTTER_ACTOR_IS_REALIZED (self))
766     {
767       /* all bets are off during reparent when we're potentially realized,
768        * but should not be according to invariants
769        */
770       if (!CLUTTER_ACTOR_IN_REPARENT (self))
771         {
772           if (priv->parent == NULL)
773             {
774               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
775                 {
776                 }
777               else
778                 g_warning ("Realized non-toplevel actor '%s' should "
779                            "have a parent",
780                            _clutter_actor_get_debug_name (self));
781             }
782           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
783             {
784               g_warning ("Realized actor %s has an unrealized parent %s",
785                          _clutter_actor_get_debug_name (self),
786                          _clutter_actor_get_debug_name (priv->parent));
787             }
788         }
789     }
790
791   if (CLUTTER_ACTOR_IS_MAPPED (self))
792     {
793       if (!CLUTTER_ACTOR_IS_REALIZED (self))
794         g_warning ("Actor '%s' is mapped but not realized",
795                    _clutter_actor_get_debug_name (self));
796
797       /* remaining bets are off during reparent when we're potentially
798        * mapped, but should not be according to invariants
799        */
800       if (!CLUTTER_ACTOR_IN_REPARENT (self))
801         {
802           if (priv->parent == NULL)
803             {
804               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
805                 {
806                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
807                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
808                     {
809                       g_warning ("Toplevel actor '%s' is mapped "
810                                  "but not visible",
811                                  _clutter_actor_get_debug_name (self));
812                     }
813                 }
814               else
815                 {
816                   g_warning ("Mapped actor '%s' should have a parent",
817                              _clutter_actor_get_debug_name (self));
818                 }
819             }
820           else
821             {
822               ClutterActor *iter = self;
823
824               /* check for the enable_paint_unmapped flag on the actor
825                * and parents; if the flag is enabled at any point of this
826                * branch of the scene graph then all the later checks
827                * become pointless
828                */
829               while (iter != NULL)
830                 {
831                   if (iter->priv->enable_paint_unmapped)
832                     return;
833
834                   iter = iter->priv->parent;
835                 }
836
837               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
838                 {
839                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
840                              "is not visible",
841                              _clutter_actor_get_debug_name (self),
842                              _clutter_actor_get_debug_name (priv->parent));
843                 }
844
845               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
846                 {
847                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
848                              "is not realized",
849                              _clutter_actor_get_debug_name (self),
850                              _clutter_actor_get_debug_name (priv->parent));
851                 }
852
853               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
854                 {
855                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
856                     g_warning ("Actor '%s' is mapped but its non-toplevel "
857                                "parent '%s' is not mapped",
858                                _clutter_actor_get_debug_name (self),
859                                _clutter_actor_get_debug_name (priv->parent));
860                 }
861             }
862         }
863     }
864 }
865
866 #endif /* CLUTTER_ENABLE_DEBUG */
867
868 static void
869 clutter_actor_set_mapped (ClutterActor *self,
870                           gboolean      mapped)
871 {
872   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
873     return;
874
875   if (mapped)
876     {
877       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
878       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
879     }
880   else
881     {
882       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
883       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
884     }
885 }
886
887 /* this function updates the mapped and realized states according to
888  * invariants, in the appropriate order.
889  */
890 static void
891 clutter_actor_update_map_state (ClutterActor  *self,
892                                 MapStateChange change)
893 {
894   gboolean was_mapped;
895
896   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
897
898   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
899     {
900       /* the mapped flag on top-level actors must be set by the
901        * per-backend implementation because it might be asynchronous.
902        *
903        * That is, the MAPPED flag on toplevels currently tracks the X
904        * server mapped-ness of the window, while the expected behavior
905        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
906        * This creates some weird complexity by breaking the invariant
907        * that if we're visible and all ancestors shown then we are
908        * also mapped - instead, we are mapped if all ancestors
909        * _possibly excepting_ the stage are mapped. The stage
910        * will map/unmap for example when it is minimized or
911        * moved to another workspace.
912        *
913        * So, the only invariant on the stage is that if visible it
914        * should be realized, and that it has to be visible to be
915        * mapped.
916        */
917       if (CLUTTER_ACTOR_IS_VISIBLE (self))
918         clutter_actor_realize (self);
919
920       switch (change)
921         {
922         case MAP_STATE_CHECK:
923           break;
924
925         case MAP_STATE_MAKE_MAPPED:
926           g_assert (!was_mapped);
927           clutter_actor_set_mapped (self, TRUE);
928           break;
929
930         case MAP_STATE_MAKE_UNMAPPED:
931           g_assert (was_mapped);
932           clutter_actor_set_mapped (self, FALSE);
933           break;
934
935         case MAP_STATE_MAKE_UNREALIZED:
936           /* we only use MAKE_UNREALIZED in unparent,
937            * and unparenting a stage isn't possible.
938            * If someone wants to just unrealize a stage
939            * then clutter_actor_unrealize() doesn't
940            * go through this codepath.
941            */
942           g_warning ("Trying to force unrealize stage is not allowed");
943           break;
944         }
945
946       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
947           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
948           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
949         {
950           g_warning ("Clutter toplevel of type '%s' is not visible, but "
951                      "it is somehow still mapped",
952                      _clutter_actor_get_debug_name (self));
953         }
954     }
955   else
956     {
957       ClutterActorPrivate *priv = self->priv;
958       ClutterActor *parent = priv->parent;
959       gboolean should_be_mapped;
960       gboolean may_be_realized;
961       gboolean must_be_realized;
962
963       should_be_mapped = FALSE;
964       may_be_realized = TRUE;
965       must_be_realized = FALSE;
966
967       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
968         {
969           may_be_realized = FALSE;
970         }
971       else
972         {
973           /* Maintain invariant that if parent is mapped, and we are
974            * visible, then we are mapped ...  unless parent is a
975            * stage, in which case we map regardless of parent's map
976            * state but do require stage to be visible and realized.
977            *
978            * If parent is realized, that does not force us to be
979            * realized; but if parent is unrealized, that does force
980            * us to be unrealized.
981            *
982            * The reason we don't force children to realize with
983            * parents is _clutter_actor_rerealize(); if we require that
984            * a realized parent means children are realized, then to
985            * unrealize an actor we would have to unrealize its
986            * parents, which would end up meaning unrealizing and
987            * hiding the entire stage. So we allow unrealizing a
988            * child (as long as that child is not mapped) while that
989            * child still has a realized parent.
990            *
991            * Also, if we unrealize from leaf nodes to root, and
992            * realize from root to leaf, the invariants are never
993            * violated if we allow children to be unrealized
994            * while parents are realized.
995            *
996            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
997            * to force us to unmap, even though parent is still
998            * mapped. This is because we're unmapping from leaf nodes
999            * up to root nodes.
1000            */
1001           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1002               change != MAP_STATE_MAKE_UNMAPPED)
1003             {
1004               gboolean parent_is_visible_realized_toplevel;
1005
1006               parent_is_visible_realized_toplevel =
1007                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1008                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1009                  CLUTTER_ACTOR_IS_REALIZED (parent));
1010
1011               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1012                   parent_is_visible_realized_toplevel)
1013                 {
1014                   must_be_realized = TRUE;
1015                   should_be_mapped = TRUE;
1016                 }
1017             }
1018
1019           /* if the actor has been set to be painted even if unmapped
1020            * then we should map it and check for realization as well;
1021            * this is an override for the branch of the scene graph
1022            * which begins with this node
1023            */
1024           if (priv->enable_paint_unmapped)
1025             {
1026               if (priv->parent == NULL)
1027                 g_warning ("Attempting to map an unparented actor '%s'",
1028                            _clutter_actor_get_debug_name (self));
1029
1030               should_be_mapped = TRUE;
1031               must_be_realized = TRUE;
1032             }
1033
1034           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1035             may_be_realized = FALSE;
1036         }
1037
1038       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1039         {
1040           if (parent == NULL)
1041             g_warning ("Attempting to map a child that does not "
1042                        "meet the necessary invariants: the actor '%s' "
1043                        "has no parent",
1044                        _clutter_actor_get_debug_name (self));
1045           else
1046             g_warning ("Attempting to map a child that does not "
1047                        "meet the necessary invariants: the actor '%s' "
1048                        "is parented to an unmapped actor '%s'",
1049                        _clutter_actor_get_debug_name (self),
1050                        _clutter_actor_get_debug_name (priv->parent));
1051         }
1052
1053       /* If in reparent, we temporarily suspend unmap and unrealize.
1054        *
1055        * We want to go in the order "realize, map" and "unmap, unrealize"
1056        */
1057
1058       /* Unmap */
1059       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1060         clutter_actor_set_mapped (self, FALSE);
1061
1062       /* Realize */
1063       if (must_be_realized)
1064         clutter_actor_realize (self);
1065
1066       /* if we must be realized then we may be, presumably */
1067       g_assert (!(must_be_realized && !may_be_realized));
1068
1069       /* Unrealize */
1070       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1071         clutter_actor_unrealize_not_hiding (self);
1072
1073       /* Map */
1074       if (should_be_mapped)
1075         {
1076           if (!must_be_realized)
1077             g_warning ("Somehow we think actor '%s' should be mapped but "
1078                        "not realized, which isn't allowed",
1079                        _clutter_actor_get_debug_name (self));
1080
1081           /* realization is allowed to fail (though I don't know what
1082            * an app is supposed to do about that - shouldn't it just
1083            * be a g_error? anyway, we have to avoid mapping if this
1084            * happens)
1085            */
1086           if (CLUTTER_ACTOR_IS_REALIZED (self))
1087             clutter_actor_set_mapped (self, TRUE);
1088         }
1089     }
1090
1091 #ifdef CLUTTER_ENABLE_DEBUG
1092   /* check all invariants were kept */
1093   clutter_actor_verify_map_state (self);
1094 #endif
1095 }
1096
1097 static void
1098 clutter_actor_real_map (ClutterActor *self)
1099 {
1100   ClutterActorPrivate *priv = self->priv;
1101   ClutterActor *stage, *iter;
1102
1103   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1104
1105   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1106                 _clutter_actor_get_debug_name (self));
1107
1108   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1109
1110   stage = _clutter_actor_get_stage_internal (self);
1111   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1112
1113   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1114                 priv->pick_id,
1115                 _clutter_actor_get_debug_name (self));
1116
1117   /* notify on parent mapped before potentially mapping
1118    * children, so apps see a top-down notification.
1119    */
1120   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1121
1122   for (iter = self->priv->first_child;
1123        iter != NULL;
1124        iter = iter->priv->next_sibling)
1125     {
1126       clutter_actor_map (iter);
1127     }
1128 }
1129
1130 /**
1131  * clutter_actor_map:
1132  * @self: A #ClutterActor
1133  *
1134  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1135  * and realizes its children if they are visible. Does nothing if the
1136  * actor is not visible.
1137  *
1138  * Calling this function is strongly disencouraged: the default
1139  * implementation of #ClutterActorClass.map() will map all the children
1140  * of an actor when mapping its parent.
1141  *
1142  * When overriding map, it is mandatory to chain up to the parent
1143  * implementation.
1144  *
1145  * Since: 1.0
1146  */
1147 void
1148 clutter_actor_map (ClutterActor *self)
1149 {
1150   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1151
1152   if (CLUTTER_ACTOR_IS_MAPPED (self))
1153     return;
1154
1155   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1156     return;
1157
1158   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1159 }
1160
1161 static void
1162 clutter_actor_real_unmap (ClutterActor *self)
1163 {
1164   ClutterActorPrivate *priv = self->priv;
1165   ClutterActor *iter;
1166
1167   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1168
1169   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1170                 _clutter_actor_get_debug_name (self));
1171
1172   for (iter = self->priv->first_child;
1173        iter != NULL;
1174        iter = iter->priv->next_sibling)
1175     {
1176       clutter_actor_unmap (iter);
1177     }
1178
1179   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1180
1181   /* clear the contents of the last paint volume, so that hiding + moving +
1182    * showing will not result in the wrong area being repainted
1183    */
1184   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1185   priv->last_paint_volume_valid = TRUE;
1186
1187   /* notify on parent mapped after potentially unmapping
1188    * children, so apps see a bottom-up notification.
1189    */
1190   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1191
1192   /* relinquish keyboard focus if we were unmapped while owning it */
1193   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1194     {
1195       ClutterStage *stage;
1196
1197       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1198
1199       if (stage != NULL)
1200         _clutter_stage_release_pick_id (stage, priv->pick_id);
1201
1202       priv->pick_id = -1;
1203
1204       if (stage != NULL &&
1205           clutter_stage_get_key_focus (stage) == self)
1206         {
1207           clutter_stage_set_key_focus (stage, NULL);
1208         }
1209     }
1210 }
1211
1212 /**
1213  * clutter_actor_unmap:
1214  * @self: A #ClutterActor
1215  *
1216  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1217  * unmaps its children if they were mapped.
1218  *
1219  * Calling this function is not encouraged: the default #ClutterActor
1220  * implementation of #ClutterActorClass.unmap() will also unmap any
1221  * eventual children by default when their parent is unmapped.
1222  *
1223  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1224  * chain up to the parent implementation.
1225  *
1226  * <note>It is important to note that the implementation of the
1227  * #ClutterActorClass.unmap() virtual function may be called after
1228  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1229  * implementation, but it is guaranteed to be called before the
1230  * #GObjectClass.finalize() implementation.</note>
1231  *
1232  * Since: 1.0
1233  */
1234 void
1235 clutter_actor_unmap (ClutterActor *self)
1236 {
1237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1238
1239   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1240     return;
1241
1242   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1243 }
1244
1245 static void
1246 clutter_actor_real_show (ClutterActor *self)
1247 {
1248   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1249     {
1250       ClutterActorPrivate *priv = self->priv;
1251
1252       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1253
1254       /* we notify on the "visible" flag in the clutter_actor_show()
1255        * wrapper so the entire show signal emission completes first
1256        * (?)
1257        */
1258       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1259
1260       /* we queue a relayout unless the actor is inside a
1261        * container that explicitly told us not to
1262        */
1263       if (priv->parent != NULL &&
1264           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1265         {
1266           /* While an actor is hidden the parent may not have
1267            * allocated/requested so we need to start from scratch
1268            * and avoid the short-circuiting in
1269            * clutter_actor_queue_relayout().
1270            */
1271           priv->needs_width_request  = FALSE;
1272           priv->needs_height_request = FALSE;
1273           priv->needs_allocation     = FALSE;
1274           clutter_actor_queue_relayout (self);
1275         }
1276     }
1277 }
1278
1279 static inline void
1280 set_show_on_set_parent (ClutterActor *self,
1281                         gboolean      set_show)
1282 {
1283   ClutterActorPrivate *priv = self->priv;
1284
1285   set_show = !!set_show;
1286
1287   if (priv->show_on_set_parent == set_show)
1288     return;
1289
1290   if (priv->parent == NULL)
1291     {
1292       priv->show_on_set_parent = set_show;
1293       g_object_notify_by_pspec (G_OBJECT (self),
1294                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1295     }
1296 }
1297
1298 /**
1299  * clutter_actor_show:
1300  * @self: A #ClutterActor
1301  *
1302  * Flags an actor to be displayed. An actor that isn't shown will not
1303  * be rendered on the stage.
1304  *
1305  * Actors are visible by default.
1306  *
1307  * If this function is called on an actor without a parent, the
1308  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1309  * effect.
1310  */
1311 void
1312 clutter_actor_show (ClutterActor *self)
1313 {
1314   ClutterActorPrivate *priv;
1315
1316   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1317
1318   /* simple optimization */
1319   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1320     {
1321       /* we still need to set the :show-on-set-parent property, in
1322        * case show() is called on an unparented actor
1323        */
1324       set_show_on_set_parent (self, TRUE);
1325       return;
1326     }
1327
1328 #ifdef CLUTTER_ENABLE_DEBUG
1329   clutter_actor_verify_map_state (self);
1330 #endif
1331
1332   priv = self->priv;
1333
1334   g_object_freeze_notify (G_OBJECT (self));
1335
1336   set_show_on_set_parent (self, TRUE);
1337
1338   g_signal_emit (self, actor_signals[SHOW], 0);
1339   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1340
1341   if (priv->parent != NULL)
1342     clutter_actor_queue_redraw (priv->parent);
1343
1344   g_object_thaw_notify (G_OBJECT (self));
1345 }
1346
1347 /**
1348  * clutter_actor_show_all:
1349  * @self: a #ClutterActor
1350  *
1351  * Calls clutter_actor_show() on all children of an actor (if any).
1352  *
1353  * Since: 0.2
1354  *
1355  * Deprecated: 1.10: Actors are visible by default
1356  */
1357 void
1358 clutter_actor_show_all (ClutterActor *self)
1359 {
1360   ClutterActorClass *klass;
1361
1362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1363
1364   klass = CLUTTER_ACTOR_GET_CLASS (self);
1365   if (klass->show_all)
1366     klass->show_all (self);
1367 }
1368
1369 void
1370 clutter_actor_real_hide (ClutterActor *self)
1371 {
1372   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1373     {
1374       ClutterActorPrivate *priv = self->priv;
1375
1376       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1377
1378       /* we notify on the "visible" flag in the clutter_actor_hide()
1379        * wrapper so the entire hide signal emission completes first
1380        * (?)
1381        */
1382       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1383
1384       /* we queue a relayout unless the actor is inside a
1385        * container that explicitly told us not to
1386        */
1387       if (priv->parent != NULL &&
1388           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1389         clutter_actor_queue_relayout (priv->parent);
1390     }
1391 }
1392
1393 /**
1394  * clutter_actor_hide:
1395  * @self: A #ClutterActor
1396  *
1397  * Flags an actor to be hidden. A hidden actor will not be
1398  * rendered on the stage.
1399  *
1400  * Actors are visible by default.
1401  *
1402  * If this function is called on an actor without a parent, the
1403  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1404  * as a side-effect.
1405  */
1406 void
1407 clutter_actor_hide (ClutterActor *self)
1408 {
1409   ClutterActorPrivate *priv;
1410
1411   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1412
1413   /* simple optimization */
1414   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1415     {
1416       /* we still need to set the :show-on-set-parent property, in
1417        * case hide() is called on an unparented actor
1418        */
1419       set_show_on_set_parent (self, FALSE);
1420       return;
1421     }
1422
1423 #ifdef CLUTTER_ENABLE_DEBUG
1424   clutter_actor_verify_map_state (self);
1425 #endif
1426
1427   priv = self->priv;
1428
1429   g_object_freeze_notify (G_OBJECT (self));
1430
1431   set_show_on_set_parent (self, FALSE);
1432
1433   g_signal_emit (self, actor_signals[HIDE], 0);
1434   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1435
1436   if (priv->parent != NULL)
1437     clutter_actor_queue_redraw (priv->parent);
1438
1439   g_object_thaw_notify (G_OBJECT (self));
1440 }
1441
1442 /**
1443  * clutter_actor_hide_all:
1444  * @self: a #ClutterActor
1445  *
1446  * Calls clutter_actor_hide() on all child actors (if any).
1447  *
1448  * Since: 0.2
1449  *
1450  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1451  *   prevent its children from being painted as well.
1452  */
1453 void
1454 clutter_actor_hide_all (ClutterActor *self)
1455 {
1456   ClutterActorClass *klass;
1457
1458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1459
1460   klass = CLUTTER_ACTOR_GET_CLASS (self);
1461   if (klass->hide_all)
1462     klass->hide_all (self);
1463 }
1464
1465 /**
1466  * clutter_actor_realize:
1467  * @self: A #ClutterActor
1468  *
1469  * Realization informs the actor that it is attached to a stage. It
1470  * can use this to allocate resources if it wanted to delay allocation
1471  * until it would be rendered. However it is perfectly acceptable for
1472  * an actor to create resources before being realized because Clutter
1473  * only ever has a single rendering context so that actor is free to
1474  * be moved from one stage to another.
1475  *
1476  * This function does nothing if the actor is already realized.
1477  *
1478  * Because a realized actor must have realized parent actors, calling
1479  * clutter_actor_realize() will also realize all parents of the actor.
1480  *
1481  * This function does not realize child actors, except in the special
1482  * case that realizing the stage, when the stage is visible, will
1483  * suddenly map (and thus realize) the children of the stage.
1484  **/
1485 void
1486 clutter_actor_realize (ClutterActor *self)
1487 {
1488   ClutterActorPrivate *priv;
1489
1490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1491
1492   priv = self->priv;
1493
1494 #ifdef CLUTTER_ENABLE_DEBUG
1495   clutter_actor_verify_map_state (self);
1496 #endif
1497
1498   if (CLUTTER_ACTOR_IS_REALIZED (self))
1499     return;
1500
1501   /* To be realized, our parent actors must be realized first.
1502    * This will only succeed if we're inside a toplevel.
1503    */
1504   if (priv->parent != NULL)
1505     clutter_actor_realize (priv->parent);
1506
1507   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1508     {
1509       /* toplevels can be realized at any time */
1510     }
1511   else
1512     {
1513       /* "Fail" the realization if parent is missing or unrealized;
1514        * this should really be a g_warning() not some kind of runtime
1515        * failure; how can an app possibly recover? Instead it's a bug
1516        * in the app and the app should get an explanatory warning so
1517        * someone can fix it. But for now it's too hard to fix this
1518        * because e.g. ClutterTexture needs reworking.
1519        */
1520       if (priv->parent == NULL ||
1521           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1522         return;
1523     }
1524
1525   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1526
1527   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1528   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1529
1530   g_signal_emit (self, actor_signals[REALIZE], 0);
1531
1532   /* Stage actor is allowed to unset the realized flag again in its
1533    * default signal handler, though that is a pathological situation.
1534    */
1535
1536   /* If realization "failed" we'll have to update child state. */
1537   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1538 }
1539
1540 void
1541 clutter_actor_real_unrealize (ClutterActor *self)
1542 {
1543   /* we must be unmapped (implying our children are also unmapped) */
1544   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1545 }
1546
1547 /**
1548  * clutter_actor_unrealize:
1549  * @self: A #ClutterActor
1550  *
1551  * Unrealization informs the actor that it may be being destroyed or
1552  * moved to another stage. The actor may want to destroy any
1553  * underlying graphics resources at this point. However it is
1554  * perfectly acceptable for it to retain the resources until the actor
1555  * is destroyed because Clutter only ever uses a single rendering
1556  * context and all of the graphics resources are valid on any stage.
1557  *
1558  * Because mapped actors must be realized, actors may not be
1559  * unrealized if they are mapped. This function hides the actor to be
1560  * sure it isn't mapped, an application-visible side effect that you
1561  * may not be expecting.
1562  *
1563  * This function should not be called by application code.
1564  */
1565 void
1566 clutter_actor_unrealize (ClutterActor *self)
1567 {
1568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1569   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1570
1571 /* This function should not really be in the public API, because
1572  * there isn't a good reason to call it. ClutterActor will already
1573  * unrealize things for you when it's important to do so.
1574  *
1575  * If you were using clutter_actor_unrealize() in a dispose
1576  * implementation, then don't, just chain up to ClutterActor's
1577  * dispose.
1578  *
1579  * If you were using clutter_actor_unrealize() to implement
1580  * unrealizing children of your container, then don't, ClutterActor
1581  * will already take care of that.
1582  *
1583  * If you were using clutter_actor_unrealize() to re-realize to
1584  * create your resources in a different way, then use
1585  * _clutter_actor_rerealize() (inside Clutter) or just call your
1586  * code that recreates your resources directly (outside Clutter).
1587  */
1588
1589 #ifdef CLUTTER_ENABLE_DEBUG
1590   clutter_actor_verify_map_state (self);
1591 #endif
1592
1593   clutter_actor_hide (self);
1594
1595   clutter_actor_unrealize_not_hiding (self);
1596 }
1597
1598 static ClutterActorTraverseVisitFlags
1599 unrealize_actor_before_children_cb (ClutterActor *self,
1600                                     int depth,
1601                                     void *user_data)
1602 {
1603   /* If an actor is already unrealized we know its children have also
1604    * already been unrealized... */
1605   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1606     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1607
1608   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1609
1610   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1611 }
1612
1613 static ClutterActorTraverseVisitFlags
1614 unrealize_actor_after_children_cb (ClutterActor *self,
1615                                    int depth,
1616                                    void *user_data)
1617 {
1618   /* We want to unset the realized flag only _after_
1619    * child actors are unrealized, to maintain invariants.
1620    */
1621   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1622   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1623   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1624 }
1625
1626 /*
1627  * clutter_actor_unrealize_not_hiding:
1628  * @self: A #ClutterActor
1629  *
1630  * Unrealization informs the actor that it may be being destroyed or
1631  * moved to another stage. The actor may want to destroy any
1632  * underlying graphics resources at this point. However it is
1633  * perfectly acceptable for it to retain the resources until the actor
1634  * is destroyed because Clutter only ever uses a single rendering
1635  * context and all of the graphics resources are valid on any stage.
1636  *
1637  * Because mapped actors must be realized, actors may not be
1638  * unrealized if they are mapped. You must hide the actor or one of
1639  * its parents before attempting to unrealize.
1640  *
1641  * This function is separate from clutter_actor_unrealize() because it
1642  * does not automatically hide the actor.
1643  * Actors need not be hidden to be unrealized, they just need to
1644  * be unmapped. In fact we don't want to mess up the application's
1645  * setting of the "visible" flag, so hiding is very undesirable.
1646  *
1647  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1648  * backward compatibility.
1649  */
1650 static void
1651 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1652 {
1653   _clutter_actor_traverse (self,
1654                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1655                            unrealize_actor_before_children_cb,
1656                            unrealize_actor_after_children_cb,
1657                            NULL);
1658 }
1659
1660 /*
1661  * _clutter_actor_rerealize:
1662  * @self: A #ClutterActor
1663  * @callback: Function to call while unrealized
1664  * @data: data for callback
1665  *
1666  * If an actor is already unrealized, this just calls the callback.
1667  *
1668  * If it is realized, it unrealizes temporarily, calls the callback,
1669  * and then re-realizes the actor.
1670  *
1671  * As a side effect, leaves all children of the actor unrealized if
1672  * the actor was realized but not showing.  This is because when we
1673  * unrealize the actor temporarily we must unrealize its children
1674  * (e.g. children of a stage can't be realized if stage window is
1675  * gone). And we aren't clever enough to save the realization state of
1676  * all children. In most cases this should not matter, because
1677  * the children will automatically realize when they next become mapped.
1678  */
1679 void
1680 _clutter_actor_rerealize (ClutterActor    *self,
1681                           ClutterCallback  callback,
1682                           void            *data)
1683 {
1684   gboolean was_mapped;
1685   gboolean was_showing;
1686   gboolean was_realized;
1687
1688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1689
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691   clutter_actor_verify_map_state (self);
1692 #endif
1693
1694   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1695   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1696   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1697
1698   /* Must be unmapped to unrealize. Note we only have to hide this
1699    * actor if it was mapped (if all parents were showing).  If actor
1700    * is merely visible (but not mapped), then that's fine, we can
1701    * leave it visible.
1702    */
1703   if (was_mapped)
1704     clutter_actor_hide (self);
1705
1706   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1707
1708   /* unrealize self and all children */
1709   clutter_actor_unrealize_not_hiding (self);
1710
1711   if (callback != NULL)
1712     {
1713       (* callback) (self, data);
1714     }
1715
1716   if (was_showing)
1717     clutter_actor_show (self); /* will realize only if mapping implies it */
1718   else if (was_realized)
1719     clutter_actor_realize (self); /* realize self and all parents */
1720 }
1721
1722 static void
1723 clutter_actor_real_pick (ClutterActor       *self,
1724                          const ClutterColor *color)
1725 {
1726   /* the default implementation is just to paint a rectangle
1727    * with the same size of the actor using the passed color
1728    */
1729   if (clutter_actor_should_pick_paint (self))
1730     {
1731       ClutterActorBox box = { 0, };
1732       float width, height;
1733
1734       clutter_actor_get_allocation_box (self, &box);
1735
1736       width = box.x2 - box.x1;
1737       height = box.y2 - box.y1;
1738
1739       cogl_set_source_color4ub (color->red,
1740                                 color->green,
1741                                 color->blue,
1742                                 color->alpha);
1743
1744       cogl_rectangle (0, 0, width, height);
1745     }
1746
1747   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1748    * with existing container classes that override the pick() virtual
1749    * and chain up to the default implementation - otherwise we'll end up
1750    * painting our children twice.
1751    *
1752    * this has to go away for 2.0; hopefully along the pick() itself.
1753    */
1754   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1755     {
1756       ClutterActor *iter;
1757
1758       for (iter = self->priv->first_child;
1759            iter != NULL;
1760            iter = iter->priv->next_sibling)
1761         clutter_actor_paint (iter);
1762     }
1763 }
1764
1765 /**
1766  * clutter_actor_should_pick_paint:
1767  * @self: A #ClutterActor
1768  *
1769  * Should be called inside the implementation of the
1770  * #ClutterActor::pick virtual function in order to check whether
1771  * the actor should paint itself in pick mode or not.
1772  *
1773  * This function should never be called directly by applications.
1774  *
1775  * Return value: %TRUE if the actor should paint its silhouette,
1776  *   %FALSE otherwise
1777  */
1778 gboolean
1779 clutter_actor_should_pick_paint (ClutterActor *self)
1780 {
1781   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1782
1783   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1784       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1785        CLUTTER_ACTOR_IS_REACTIVE (self)))
1786     return TRUE;
1787
1788   return FALSE;
1789 }
1790
1791 static void
1792 clutter_actor_real_get_preferred_width (ClutterActor *self,
1793                                         gfloat        for_height,
1794                                         gfloat       *min_width_p,
1795                                         gfloat       *natural_width_p)
1796 {
1797   ClutterActorPrivate *priv = self->priv;
1798
1799   if (priv->n_children != 0 &&
1800       priv->layout_manager != NULL)
1801     {
1802       ClutterContainer *container = CLUTTER_CONTAINER (self);
1803
1804       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1805                     "for the preferred width",
1806                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1807                     priv->layout_manager);
1808
1809       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1810                                                   container,
1811                                                   for_height,
1812                                                   min_width_p,
1813                                                   natural_width_p);
1814
1815       return;
1816     }
1817
1818   /* Default implementation is always 0x0, usually an actor
1819    * using this default is relying on someone to set the
1820    * request manually
1821    */
1822   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1823
1824   if (min_width_p)
1825     *min_width_p = 0;
1826
1827   if (natural_width_p)
1828     *natural_width_p = 0;
1829 }
1830
1831 static void
1832 clutter_actor_real_get_preferred_height (ClutterActor *self,
1833                                          gfloat        for_width,
1834                                          gfloat       *min_height_p,
1835                                          gfloat       *natural_height_p)
1836 {
1837   ClutterActorPrivate *priv = self->priv;
1838
1839   if (priv->n_children != 0 &&
1840       priv->layout_manager != NULL)
1841     {
1842       ClutterContainer *container = CLUTTER_CONTAINER (self);
1843
1844       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1845                     "for the preferred height",
1846                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1847                     priv->layout_manager);
1848
1849       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1850                                                    container,
1851                                                    for_width,
1852                                                    min_height_p,
1853                                                    natural_height_p);
1854
1855       return;
1856     }
1857   /* Default implementation is always 0x0, usually an actor
1858    * using this default is relying on someone to set the
1859    * request manually
1860    */
1861   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1862
1863   if (min_height_p)
1864     *min_height_p = 0;
1865
1866   if (natural_height_p)
1867     *natural_height_p = 0;
1868 }
1869
1870 static void
1871 clutter_actor_store_old_geometry (ClutterActor    *self,
1872                                   ClutterActorBox *box)
1873 {
1874   *box = self->priv->allocation;
1875 }
1876
1877 static inline void
1878 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1879                                           const ClutterActorBox *old)
1880 {
1881   ClutterActorPrivate *priv = self->priv;
1882   GObject *obj = G_OBJECT (self);
1883
1884   g_object_freeze_notify (obj);
1885
1886   /* to avoid excessive requisition or allocation cycles we
1887    * use the cached values.
1888    *
1889    * - if we don't have an allocation we assume that we need
1890    *   to notify anyway
1891    * - if we don't have a width or a height request we notify
1892    *   width and height
1893    * - if we have a valid allocation then we check the old
1894    *   bounding box with the current allocation and we notify
1895    *   the changes
1896    */
1897   if (priv->needs_allocation)
1898     {
1899       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1900       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1903     }
1904   else if (priv->needs_width_request || priv->needs_height_request)
1905     {
1906       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1907       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1908     }
1909   else
1910     {
1911       gfloat xu, yu;
1912       gfloat widthu, heightu;
1913
1914       xu = priv->allocation.x1;
1915       yu = priv->allocation.y1;
1916       widthu = priv->allocation.x2 - priv->allocation.x1;
1917       heightu = priv->allocation.y2 - priv->allocation.y1;
1918
1919       if (xu != old->x1)
1920         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1921
1922       if (yu != old->y1)
1923         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1924
1925       if (widthu != (old->x2 - old->x1))
1926         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1927
1928       if (heightu != (old->y2 - old->y1))
1929         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1930     }
1931
1932   g_object_thaw_notify (obj);
1933 }
1934
1935 /*< private >
1936  * clutter_actor_set_allocation_internal:
1937  * @self: a #ClutterActor
1938  * @box: a #ClutterActorBox
1939  * @flags: allocation flags
1940  *
1941  * Stores the allocation of @self.
1942  *
1943  * This function only performs basic storage and property notification.
1944  *
1945  * This function should be called by clutter_actor_set_allocation()
1946  * and by the default implementation of #ClutterActorClass.allocate().
1947  *
1948  * Return value: %TRUE if the allocation of the #ClutterActor has been
1949  *   changed, and %FALSE otherwise
1950  */
1951 static inline gboolean
1952 clutter_actor_set_allocation_internal (ClutterActor           *self,
1953                                        const ClutterActorBox  *box,
1954                                        ClutterAllocationFlags  flags)
1955 {
1956   ClutterActorPrivate *priv = self->priv;
1957   GObject *obj;
1958   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1959   gboolean flags_changed;
1960   gboolean retval;
1961   ClutterActorBox old_alloc = { 0, };
1962
1963   obj = G_OBJECT (self);
1964
1965   g_object_freeze_notify (obj);
1966
1967   clutter_actor_store_old_geometry (self, &old_alloc);
1968
1969   x1_changed = priv->allocation.x1 != box->x1;
1970   y1_changed = priv->allocation.y1 != box->y1;
1971   x2_changed = priv->allocation.x2 != box->x2;
1972   y2_changed = priv->allocation.y2 != box->y2;
1973
1974   flags_changed = priv->allocation_flags != flags;
1975
1976   priv->allocation = *box;
1977   priv->allocation_flags = flags;
1978
1979   /* allocation is authoritative */
1980   priv->needs_width_request = FALSE;
1981   priv->needs_height_request = FALSE;
1982   priv->needs_allocation = FALSE;
1983
1984   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1985     {
1986       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1987                     _clutter_actor_get_debug_name (self));
1988
1989       priv->transform_valid = FALSE;
1990
1991       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1992
1993       retval = TRUE;
1994     }
1995   else
1996     retval = FALSE;
1997
1998   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
1999
2000   g_object_thaw_notify (obj);
2001
2002   return retval;
2003 }
2004
2005 static void clutter_actor_real_allocate (ClutterActor           *self,
2006                                          const ClutterActorBox  *box,
2007                                          ClutterAllocationFlags  flags);
2008
2009 static inline void
2010 clutter_actor_maybe_layout_children (ClutterActor           *self,
2011                                      const ClutterActorBox  *allocation,
2012                                      ClutterAllocationFlags  flags)
2013 {
2014   ClutterActorPrivate *priv = self->priv;
2015
2016   /* this is going to be a bit hard to follow, so let's put an explanation
2017    * here.
2018    *
2019    * we want ClutterActor to have a default layout manager if the actor was
2020    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2021    *
2022    * we also want any subclass of ClutterActor that does not override the
2023    * ::allocate() virtual function to delegate to a layout manager.
2024    *
2025    * finally, we want to allow people subclassing ClutterActor and overriding
2026    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2027    *
2028    * on the other hand, we want existing actor subclasses overriding the
2029    * ::allocate() virtual function and chaining up to the parent's
2030    * implementation to continue working without allocating their children
2031    * twice, or without entering an allocation loop.
2032    *
2033    * for the first two points, we check if the class of the actor is
2034    * overridding the ::allocate() virtual function; if it isn't, then we
2035    * follow through with checking whether we have children and a layout
2036    * manager, and eventually calling clutter_layout_manager_allocate().
2037    *
2038    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2039    * allocation flags that we got passed, and if it is present, we continue
2040    * with the check above.
2041    *
2042    * if neither of these two checks yields a positive result, we just
2043    * assume that the ::allocate() virtual function that resulted in this
2044    * function being called will also allocate the children of the actor.
2045    */
2046
2047   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2048     goto check_layout;
2049
2050   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2051     goto check_layout;
2052
2053   return;
2054
2055 check_layout:
2056   if (priv->n_children != 0 &&
2057       priv->layout_manager != NULL)
2058     {
2059       ClutterContainer *container = CLUTTER_CONTAINER (self);
2060       ClutterAllocationFlags children_flags;
2061       ClutterActorBox children_box;
2062
2063       /* normalize the box passed to the layout manager */
2064       children_box.x1 = children_box.y1 = 0.f;
2065       children_box.x2 = (allocation->x2 - allocation->x1);
2066       children_box.y2 = (allocation->y2 - allocation->y1);
2067
2068       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2069        * the actor's children, since it refers only to the current
2070        * actor's allocation.
2071        */
2072       children_flags = flags;
2073       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2074
2075       CLUTTER_NOTE (LAYOUT,
2076                     "Allocating %d children of %s "
2077                     "at { %.2f, %.2f - %.2f x %.2f } "
2078                     "using %s",
2079                     priv->n_children,
2080                     _clutter_actor_get_debug_name (self),
2081                     allocation->x1,
2082                     allocation->y1,
2083                     (allocation->x2 - allocation->x1),
2084                     (allocation->y2 - allocation->y1),
2085                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2086
2087       clutter_layout_manager_allocate (priv->layout_manager,
2088                                        container,
2089                                        &children_box,
2090                                        children_flags);
2091     }
2092 }
2093
2094 static void
2095 clutter_actor_real_allocate (ClutterActor           *self,
2096                              const ClutterActorBox  *box,
2097                              ClutterAllocationFlags  flags)
2098 {
2099   ClutterActorPrivate *priv = self->priv;
2100   gboolean changed;
2101
2102   g_object_freeze_notify (G_OBJECT (self));
2103
2104   changed = clutter_actor_set_allocation_internal (self, box, flags);
2105
2106   /* we allocate our children before we notify changes in our geometry,
2107    * so that people connecting to properties will be able to get valid
2108    * data out of the sub-tree of the scene graph that has this actor at
2109    * the root.
2110    */
2111   clutter_actor_maybe_layout_children (self, box, flags);
2112
2113   if (changed)
2114     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2115                    &priv->allocation,
2116                    priv->allocation_flags);
2117
2118   g_object_thaw_notify (G_OBJECT (self));
2119 }
2120
2121 static void
2122 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2123                                     ClutterActor *origin)
2124 {
2125   /* no point in queuing a redraw on a destroyed actor */
2126   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2127     return;
2128
2129   /* NB: We can't bail out early here if the actor is hidden in case
2130    * the actor bas been cloned. In this case the clone will need to
2131    * receive the signal so it can queue its own redraw.
2132    */
2133
2134   /* calls klass->queue_redraw in default handler */
2135   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2136 }
2137
2138 static void
2139 clutter_actor_real_queue_redraw (ClutterActor *self,
2140                                  ClutterActor *origin)
2141 {
2142   ClutterActor *parent;
2143
2144   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2145                 _clutter_actor_get_debug_name (self),
2146                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2147                                : "same actor");
2148
2149   /* no point in queuing a redraw on a destroyed actor */
2150   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2151     return;
2152
2153   /* If the queue redraw is coming from a child then the actor has
2154      become dirty and any queued effect is no longer valid */
2155   if (self != origin)
2156     {
2157       self->priv->is_dirty = TRUE;
2158       self->priv->effect_to_redraw = NULL;
2159     }
2160
2161   /* If the actor isn't visible, we still had to emit the signal
2162    * to allow for a ClutterClone, but the appearance of the parent
2163    * won't change so we don't have to propagate up the hierarchy.
2164    */
2165   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2166     return;
2167
2168   /* Although we could determine here that a full stage redraw
2169    * has already been queued and immediately bail out, we actually
2170    * guarantee that we will propagate a queue-redraw signal to our
2171    * parent at least once so that it's possible to implement a
2172    * container that tracks which of its children have queued a
2173    * redraw.
2174    */
2175   if (self->priv->propagated_one_redraw)
2176     {
2177       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2178       if (stage != NULL &&
2179           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2180         return;
2181     }
2182
2183   self->priv->propagated_one_redraw = TRUE;
2184
2185   /* notify parents, if they are all visible eventually we'll
2186    * queue redraw on the stage, which queues the redraw idle.
2187    */
2188   parent = clutter_actor_get_parent (self);
2189   if (parent != NULL)
2190     {
2191       /* this will go up recursively */
2192       _clutter_actor_signal_queue_redraw (parent, origin);
2193     }
2194 }
2195
2196 void
2197 clutter_actor_real_queue_relayout (ClutterActor *self)
2198 {
2199   ClutterActorPrivate *priv = self->priv;
2200
2201   /* no point in queueing a redraw on a destroyed actor */
2202   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2203     return;
2204
2205   priv->needs_width_request  = TRUE;
2206   priv->needs_height_request = TRUE;
2207   priv->needs_allocation     = TRUE;
2208
2209   /* reset the cached size requests */
2210   memset (priv->width_requests, 0,
2211           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2212   memset (priv->height_requests, 0,
2213           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2214
2215   /* We need to go all the way up the hierarchy */
2216   if (priv->parent != NULL)
2217     _clutter_actor_queue_only_relayout (priv->parent);
2218 }
2219
2220 /**
2221  * clutter_actor_apply_relative_transform_to_point:
2222  * @self: A #ClutterActor
2223  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2224  *   default #ClutterStage
2225  * @point: A point as #ClutterVertex
2226  * @vertex: (out caller-allocates): The translated #ClutterVertex
2227  *
2228  * Transforms @point in coordinates relative to the actor into
2229  * ancestor-relative coordinates using the relevant transform
2230  * stack (i.e. scale, rotation, etc).
2231  *
2232  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2233  * this case, the coordinates returned will be the coordinates on
2234  * the stage before the projection is applied. This is different from
2235  * the behaviour of clutter_actor_apply_transform_to_point().
2236  *
2237  * Since: 0.6
2238  */
2239 void
2240 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2241                                                  ClutterActor        *ancestor,
2242                                                  const ClutterVertex *point,
2243                                                  ClutterVertex       *vertex)
2244 {
2245   gfloat w;
2246   CoglMatrix matrix;
2247
2248   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2249   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2250   g_return_if_fail (point != NULL);
2251   g_return_if_fail (vertex != NULL);
2252
2253   *vertex = *point;
2254   w = 1.0;
2255
2256   if (ancestor == NULL)
2257     ancestor = _clutter_actor_get_stage_internal (self);
2258
2259   if (ancestor == NULL)
2260     {
2261       *vertex = *point;
2262       return;
2263     }
2264
2265   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2266   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2267 }
2268
2269 static gboolean
2270 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2271                                          const ClutterVertex *vertices_in,
2272                                          ClutterVertex *vertices_out,
2273                                          int n_vertices)
2274 {
2275   ClutterActor *stage;
2276   CoglMatrix modelview;
2277   CoglMatrix projection;
2278   float viewport[4];
2279
2280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2281
2282   stage = _clutter_actor_get_stage_internal (self);
2283
2284   /* We really can't do anything meaningful in this case so don't try
2285    * to do any transform */
2286   if (stage == NULL)
2287     return FALSE;
2288
2289   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2290    * that gets us to stage coordinates, we want to go all the way to eye
2291    * coordinates */
2292   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2293
2294   /* Fetch the projection and viewport */
2295   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2296   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2297                                &viewport[0],
2298                                &viewport[1],
2299                                &viewport[2],
2300                                &viewport[3]);
2301
2302   _clutter_util_fully_transform_vertices (&modelview,
2303                                           &projection,
2304                                           viewport,
2305                                           vertices_in,
2306                                           vertices_out,
2307                                           n_vertices);
2308
2309   return TRUE;
2310 }
2311
2312 /**
2313  * clutter_actor_apply_transform_to_point:
2314  * @self: A #ClutterActor
2315  * @point: A point as #ClutterVertex
2316  * @vertex: (out caller-allocates): The translated #ClutterVertex
2317  *
2318  * Transforms @point in coordinates relative to the actor
2319  * into screen-relative coordinates with the current actor
2320  * transformation (i.e. scale, rotation, etc)
2321  *
2322  * Since: 0.4
2323  **/
2324 void
2325 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2326                                         const ClutterVertex *point,
2327                                         ClutterVertex       *vertex)
2328 {
2329   g_return_if_fail (point != NULL);
2330   g_return_if_fail (vertex != NULL);
2331   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2332 }
2333
2334 /*
2335  * _clutter_actor_get_relative_transformation_matrix:
2336  * @self: The actor whose coordinate space you want to transform from.
2337  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2338  *            or %NULL if you want to transform all the way to eye coordinates.
2339  * @matrix: A #CoglMatrix to store the transformation
2340  *
2341  * This gets a transformation @matrix that will transform coordinates from the
2342  * coordinate space of @self into the coordinate space of @ancestor.
2343  *
2344  * For example if you need a matrix that can transform the local actor
2345  * coordinates of @self into stage coordinates you would pass the actor's stage
2346  * pointer as the @ancestor.
2347  *
2348  * If you pass %NULL then the transformation will take you all the way through
2349  * to eye coordinates. This can be useful if you want to extract the entire
2350  * modelview transform that Clutter applies before applying the projection
2351  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2352  * using cogl_set_modelview_matrix() for example then you would want a matrix
2353  * that transforms into eye coordinates.
2354  *
2355  * <note><para>This function explicitly initializes the given @matrix. If you just
2356  * want clutter to multiply a relative transformation with an existing matrix
2357  * you can use clutter_actor_apply_relative_transformation_matrix()
2358  * instead.</para></note>
2359  *
2360  */
2361 /* XXX: We should consider caching the stage relative modelview along with
2362  * the actor itself */
2363 static void
2364 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2365                                                    ClutterActor *ancestor,
2366                                                    CoglMatrix *matrix)
2367 {
2368   cogl_matrix_init_identity (matrix);
2369
2370   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2371 }
2372
2373 /* Project the given @box into stage window coordinates, writing the
2374  * transformed vertices to @verts[]. */
2375 static gboolean
2376 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2377                                           const ClutterActorBox *box,
2378                                           ClutterVertex          verts[])
2379 {
2380   ClutterVertex box_vertices[4];
2381
2382   box_vertices[0].x = box->x1;
2383   box_vertices[0].y = box->y1;
2384   box_vertices[0].z = 0;
2385   box_vertices[1].x = box->x2;
2386   box_vertices[1].y = box->y1;
2387   box_vertices[1].z = 0;
2388   box_vertices[2].x = box->x1;
2389   box_vertices[2].y = box->y2;
2390   box_vertices[2].z = 0;
2391   box_vertices[3].x = box->x2;
2392   box_vertices[3].y = box->y2;
2393   box_vertices[3].z = 0;
2394
2395   return
2396     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2397 }
2398
2399 /**
2400  * clutter_actor_get_allocation_vertices:
2401  * @self: A #ClutterActor
2402  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2403  *   against, or %NULL to use the #ClutterStage
2404  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2405  *   location for an array of 4 #ClutterVertex in which to store the result
2406  *
2407  * Calculates the transformed coordinates of the four corners of the
2408  * actor in the plane of @ancestor. The returned vertices relate to
2409  * the #ClutterActorBox coordinates as follows:
2410  * <itemizedlist>
2411  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2412  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2413  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2414  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2415  * </itemizedlist>
2416  *
2417  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2418  * this case, the coordinates returned will be the coordinates on
2419  * the stage before the projection is applied. This is different from
2420  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2421  *
2422  * Since: 0.6
2423  */
2424 void
2425 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2426                                        ClutterActor  *ancestor,
2427                                        ClutterVertex  verts[])
2428 {
2429   ClutterActorPrivate *priv;
2430   ClutterActorBox box;
2431   ClutterVertex vertices[4];
2432   CoglMatrix modelview;
2433
2434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2435   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2436
2437   if (ancestor == NULL)
2438     ancestor = _clutter_actor_get_stage_internal (self);
2439
2440   /* Fallback to a NOP transform if the actor isn't parented under a
2441    * stage. */
2442   if (ancestor == NULL)
2443     ancestor = self;
2444
2445   priv = self->priv;
2446
2447   /* if the actor needs to be allocated we force a relayout, so that
2448    * we will have valid values to use in the transformations */
2449   if (priv->needs_allocation)
2450     {
2451       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2452       if (stage)
2453         _clutter_stage_maybe_relayout (stage);
2454       else
2455         {
2456           box.x1 = box.y1 = 0;
2457           /* The result isn't really meaningful in this case but at
2458            * least try to do something *vaguely* reasonable... */
2459           clutter_actor_get_size (self, &box.x2, &box.y2);
2460         }
2461     }
2462
2463   clutter_actor_get_allocation_box (self, &box);
2464
2465   vertices[0].x = box.x1;
2466   vertices[0].y = box.y1;
2467   vertices[0].z = 0;
2468   vertices[1].x = box.x2;
2469   vertices[1].y = box.y1;
2470   vertices[1].z = 0;
2471   vertices[2].x = box.x1;
2472   vertices[2].y = box.y2;
2473   vertices[2].z = 0;
2474   vertices[3].x = box.x2;
2475   vertices[3].y = box.y2;
2476   vertices[3].z = 0;
2477
2478   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2479                                                      &modelview);
2480
2481   cogl_matrix_transform_points (&modelview,
2482                                 3,
2483                                 sizeof (ClutterVertex),
2484                                 vertices,
2485                                 sizeof (ClutterVertex),
2486                                 vertices,
2487                                 4);
2488 }
2489
2490 /**
2491  * clutter_actor_get_abs_allocation_vertices:
2492  * @self: A #ClutterActor
2493  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2494  *   of 4 #ClutterVertex where to store the result.
2495  *
2496  * Calculates the transformed screen coordinates of the four corners of
2497  * the actor; the returned vertices relate to the #ClutterActorBox
2498  * coordinates  as follows:
2499  * <itemizedlist>
2500  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2501  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2502  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2503  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2504  * </itemizedlist>
2505  *
2506  * Since: 0.4
2507  */
2508 void
2509 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2510                                            ClutterVertex  verts[])
2511 {
2512   ClutterActorPrivate *priv;
2513   ClutterActorBox actor_space_allocation;
2514
2515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2516
2517   priv = self->priv;
2518
2519   /* if the actor needs to be allocated we force a relayout, so that
2520    * the actor allocation box will be valid for
2521    * _clutter_actor_transform_and_project_box()
2522    */
2523   if (priv->needs_allocation)
2524     {
2525       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2526       /* There's nothing meaningful we can do now */
2527       if (!stage)
2528         return;
2529
2530       _clutter_stage_maybe_relayout (stage);
2531     }
2532
2533   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2534    * own coordinate space... */
2535   actor_space_allocation.x1 = 0;
2536   actor_space_allocation.y1 = 0;
2537   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2538   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2539   _clutter_actor_transform_and_project_box (self,
2540                                             &actor_space_allocation,
2541                                             verts);
2542 }
2543
2544 static void
2545 clutter_actor_real_apply_transform (ClutterActor *self,
2546                                     CoglMatrix   *matrix)
2547 {
2548   ClutterActorPrivate *priv = self->priv;
2549
2550   if (!priv->transform_valid)
2551     {
2552       CoglMatrix *transform = &priv->transform;
2553       const ClutterTransformInfo *info;
2554
2555       info = _clutter_actor_get_transform_info_or_defaults (self);
2556
2557       cogl_matrix_init_identity (transform);
2558
2559       cogl_matrix_translate (transform,
2560                              priv->allocation.x1,
2561                              priv->allocation.y1,
2562                              0.0);
2563
2564       if (priv->z)
2565         cogl_matrix_translate (transform, 0, 0, priv->z);
2566
2567       /*
2568        * because the rotation involves translations, we must scale
2569        * before applying the rotations (if we apply the scale after
2570        * the rotations, the translations included in the rotation are
2571        * not scaled and so the entire object will move on the screen
2572        * as a result of rotating it).
2573        */
2574       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2575         {
2576           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2577                                         &info->scale_center,
2578                                         cogl_matrix_scale (transform,
2579                                                            info->scale_x,
2580                                                            info->scale_y,
2581                                                            1.0));
2582         }
2583
2584       if (info->rz_angle)
2585         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2586                                       &info->rz_center,
2587                                       cogl_matrix_rotate (transform,
2588                                                           info->rz_angle,
2589                                                           0, 0, 1.0));
2590
2591       if (info->ry_angle)
2592         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2593                                       &info->ry_center,
2594                                       cogl_matrix_rotate (transform,
2595                                                           info->ry_angle,
2596                                                           0, 1.0, 0));
2597
2598       if (info->rx_angle)
2599         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2600                                       &info->rx_center,
2601                                       cogl_matrix_rotate (transform,
2602                                                           info->rx_angle,
2603                                                           1.0, 0, 0));
2604
2605       if (!clutter_anchor_coord_is_zero (&info->anchor))
2606         {
2607           gfloat x, y, z;
2608
2609           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2610           cogl_matrix_translate (transform, -x, -y, -z);
2611         }
2612
2613       priv->transform_valid = TRUE;
2614     }
2615
2616   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2617 }
2618
2619 /* Applies the transforms associated with this actor to the given
2620  * matrix. */
2621 void
2622 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2623                                           CoglMatrix *matrix)
2624 {
2625   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2626 }
2627
2628 /*
2629  * clutter_actor_apply_relative_transformation_matrix:
2630  * @self: The actor whose coordinate space you want to transform from.
2631  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2632  *            or %NULL if you want to transform all the way to eye coordinates.
2633  * @matrix: A #CoglMatrix to apply the transformation too.
2634  *
2635  * This multiplies a transform with @matrix that will transform coordinates
2636  * from the coordinate space of @self into the coordinate space of @ancestor.
2637  *
2638  * For example if you need a matrix that can transform the local actor
2639  * coordinates of @self into stage coordinates you would pass the actor's stage
2640  * pointer as the @ancestor.
2641  *
2642  * If you pass %NULL then the transformation will take you all the way through
2643  * to eye coordinates. This can be useful if you want to extract the entire
2644  * modelview transform that Clutter applies before applying the projection
2645  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2646  * using cogl_set_modelview_matrix() for example then you would want a matrix
2647  * that transforms into eye coordinates.
2648  *
2649  * <note>This function doesn't initialize the given @matrix, it simply
2650  * multiplies the requested transformation matrix with the existing contents of
2651  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2652  * before calling this function, or you can use
2653  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2654  */
2655 void
2656 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2657                                                      ClutterActor *ancestor,
2658                                                      CoglMatrix *matrix)
2659 {
2660   ClutterActor *parent;
2661
2662   /* Note we terminate before ever calling stage->apply_transform()
2663    * since that would conceptually be relative to the underlying
2664    * window OpenGL coordinates so we'd need a special @ancestor
2665    * value to represent the fake parent of the stage. */
2666   if (self == ancestor)
2667     return;
2668
2669   parent = clutter_actor_get_parent (self);
2670
2671   if (parent != NULL)
2672     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2673                                                          matrix);
2674
2675   _clutter_actor_apply_modelview_transform (self, matrix);
2676 }
2677
2678 static void
2679 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2680                                        ClutterPaintVolume *pv,
2681                                        const char *label,
2682                                        const CoglColor *color)
2683 {
2684   static CoglMaterial *outline = NULL;
2685   CoglPrimitive *prim;
2686   ClutterVertex line_ends[12 * 2];
2687   int n_vertices;
2688
2689   if (outline == NULL)
2690     outline = cogl_material_new ();
2691
2692   _clutter_paint_volume_complete (pv);
2693
2694   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2695
2696   /* Front face */
2697   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2698   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2699   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2700   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2701
2702   if (!pv->is_2d)
2703     {
2704       /* Back face */
2705       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2706       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2707       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2708       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2709
2710       /* Lines connecting front face to back face */
2711       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2712       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2713       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2714       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2715     }
2716
2717   prim = cogl_primitive_new_p3 (COGL_VERTICES_MODE_LINES, n_vertices,
2718                                 (CoglVertexP3 *)line_ends);
2719
2720   cogl_material_set_color (outline, color);
2721   cogl_set_source (outline);
2722   cogl_primitive_draw (prim);
2723   cogl_object_unref (prim);
2724
2725   if (label)
2726     {
2727       PangoLayout *layout;
2728       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2729       pango_layout_set_text (layout, label, -1);
2730       cogl_pango_render_layout (layout,
2731                                 pv->vertices[0].x,
2732                                 pv->vertices[0].y,
2733                                 color,
2734                                 0);
2735       g_object_unref (layout);
2736     }
2737 }
2738
2739 static void
2740 _clutter_actor_draw_paint_volume (ClutterActor *self)
2741 {
2742   ClutterPaintVolume *pv;
2743   CoglColor color;
2744
2745   pv = _clutter_actor_get_paint_volume_mutable (self);
2746   if (!pv)
2747     {
2748       gfloat width, height;
2749       ClutterPaintVolume fake_pv;
2750
2751       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2752       _clutter_paint_volume_init_static (&fake_pv, stage);
2753
2754       clutter_actor_get_size (self, &width, &height);
2755       clutter_paint_volume_set_width (&fake_pv, width);
2756       clutter_paint_volume_set_height (&fake_pv, height);
2757
2758       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2759       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2760                                              _clutter_actor_get_debug_name (self),
2761                                              &color);
2762
2763       clutter_paint_volume_free (&fake_pv);
2764     }
2765   else
2766     {
2767       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2768       _clutter_actor_draw_paint_volume_full (self, pv,
2769                                              _clutter_actor_get_debug_name (self),
2770                                              &color);
2771     }
2772 }
2773
2774 static void
2775 _clutter_actor_paint_cull_result (ClutterActor *self,
2776                                   gboolean success,
2777                                   ClutterCullResult result)
2778 {
2779   ClutterPaintVolume *pv;
2780   CoglColor color;
2781
2782   if (success)
2783     {
2784       if (result == CLUTTER_CULL_RESULT_IN)
2785         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2786       else if (result == CLUTTER_CULL_RESULT_OUT)
2787         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2788       else
2789         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2790     }
2791   else
2792     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2793
2794   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2795     _clutter_actor_draw_paint_volume_full (self, pv,
2796                                            _clutter_actor_get_debug_name (self),
2797                                            &color);
2798   else
2799     {
2800       PangoLayout *layout;
2801       char *label =
2802         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2803       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2804       cogl_set_source_color (&color);
2805
2806       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2807       pango_layout_set_text (layout, label, -1);
2808       cogl_pango_render_layout (layout,
2809                                 0,
2810                                 0,
2811                                 &color,
2812                                 0);
2813       g_free (label);
2814       g_object_unref (layout);
2815     }
2816 }
2817
2818 static int clone_paint_level = 0;
2819
2820 void
2821 _clutter_actor_push_clone_paint (void)
2822 {
2823   clone_paint_level++;
2824 }
2825
2826 void
2827 _clutter_actor_pop_clone_paint (void)
2828 {
2829   clone_paint_level--;
2830 }
2831
2832 static gboolean
2833 in_clone_paint (void)
2834 {
2835   return clone_paint_level > 0;
2836 }
2837
2838 /* Returns TRUE if the actor can be ignored */
2839 /* FIXME: we should return a ClutterCullResult, and
2840  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2841  * means there's no point in trying to cull descendants of the current
2842  * node. */
2843 static gboolean
2844 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2845 {
2846   ClutterActorPrivate *priv = self->priv;
2847   ClutterActor *stage;
2848   const ClutterPlane *stage_clip;
2849
2850   if (!priv->last_paint_volume_valid)
2851     {
2852       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2853                     "->last_paint_volume_valid == FALSE",
2854                     _clutter_actor_get_debug_name (self));
2855       return FALSE;
2856     }
2857
2858   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2859     return FALSE;
2860
2861   stage = _clutter_actor_get_stage_internal (self);
2862   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2863   if (G_UNLIKELY (!stage_clip))
2864     {
2865       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2866                     "No stage clip set",
2867                     _clutter_actor_get_debug_name (self));
2868       return FALSE;
2869     }
2870
2871   if (cogl_get_draw_framebuffer () !=
2872       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2873     {
2874       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2875                     "Current framebuffer doesn't correspond to stage",
2876                     _clutter_actor_get_debug_name (self));
2877       return FALSE;
2878     }
2879
2880   *result_out =
2881     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2882   return TRUE;
2883 }
2884
2885 static void
2886 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2887 {
2888   ClutterActorPrivate *priv = self->priv;
2889   const ClutterPaintVolume *pv;
2890
2891   if (priv->last_paint_volume_valid)
2892     {
2893       clutter_paint_volume_free (&priv->last_paint_volume);
2894       priv->last_paint_volume_valid = FALSE;
2895     }
2896
2897   pv = clutter_actor_get_paint_volume (self);
2898   if (!pv)
2899     {
2900       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2901                     "Actor failed to report a paint volume",
2902                     _clutter_actor_get_debug_name (self));
2903       return;
2904     }
2905
2906   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2907
2908   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2909                                             NULL); /* eye coordinates */
2910
2911   priv->last_paint_volume_valid = TRUE;
2912 }
2913
2914 static inline gboolean
2915 actor_has_shader_data (ClutterActor *self)
2916 {
2917   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2918 }
2919
2920 guint32
2921 _clutter_actor_get_pick_id (ClutterActor *self)
2922 {
2923   if (self->priv->pick_id < 0)
2924     return 0;
2925
2926   return self->priv->pick_id;
2927 }
2928
2929 /* This is the same as clutter_actor_add_effect except that it doesn't
2930    queue a redraw and it doesn't notify on the effect property */
2931 static void
2932 _clutter_actor_add_effect_internal (ClutterActor  *self,
2933                                     ClutterEffect *effect)
2934 {
2935   ClutterActorPrivate *priv = self->priv;
2936
2937   if (priv->effects == NULL)
2938     {
2939       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2940       priv->effects->actor = self;
2941     }
2942
2943   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2944 }
2945
2946 /* This is the same as clutter_actor_remove_effect except that it doesn't
2947    queue a redraw and it doesn't notify on the effect property */
2948 static void
2949 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2950                                        ClutterEffect *effect)
2951 {
2952   ClutterActorPrivate *priv = self->priv;
2953
2954   if (priv->effects == NULL)
2955     return;
2956
2957   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2958 }
2959
2960 static gboolean
2961 needs_flatten_effect (ClutterActor *self)
2962 {
2963   ClutterActorPrivate *priv = self->priv;
2964
2965   if (G_UNLIKELY (clutter_paint_debug_flags &
2966                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2967     return FALSE;
2968
2969   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2970     return TRUE;
2971   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2972     {
2973       if (clutter_actor_get_paint_opacity (self) < 255 &&
2974           clutter_actor_has_overlaps (self))
2975         return TRUE;
2976     }
2977
2978   return FALSE;
2979 }
2980
2981 static void
2982 add_or_remove_flatten_effect (ClutterActor *self)
2983 {
2984   ClutterActorPrivate *priv = self->priv;
2985
2986   /* Add or remove the flatten effect depending on the
2987      offscreen-redirect property. */
2988   if (needs_flatten_effect (self))
2989     {
2990       if (priv->flatten_effect == NULL)
2991         {
2992           ClutterActorMeta *actor_meta;
2993           gint priority;
2994
2995           priv->flatten_effect = _clutter_flatten_effect_new ();
2996           /* Keep a reference to the effect so that we can queue
2997              redraws from it */
2998           g_object_ref_sink (priv->flatten_effect);
2999
3000           /* Set the priority of the effect to high so that it will
3001              always be applied to the actor first. It uses an internal
3002              priority so that it won't be visible to applications */
3003           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3004           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3005           _clutter_actor_meta_set_priority (actor_meta, priority);
3006
3007           /* This will add the effect without queueing a redraw */
3008           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3009         }
3010     }
3011   else
3012     {
3013       if (priv->flatten_effect != NULL)
3014         {
3015           /* Destroy the effect so that it will lose its fbo cache of
3016              the actor */
3017           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3018           g_object_unref (priv->flatten_effect);
3019           priv->flatten_effect = NULL;
3020         }
3021     }
3022 }
3023
3024 static void
3025 clutter_actor_real_paint (ClutterActor *actor)
3026 {
3027   ClutterActorPrivate *priv = actor->priv;
3028   ClutterActor *iter;
3029
3030   /* paint the background color, if set */
3031   if (priv->bg_color_set)
3032     {
3033       float width, height;
3034       guint8 real_alpha;
3035
3036       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3037
3038       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3039                  * priv->bg_color.alpha
3040                  / 255;
3041
3042       cogl_set_source_color4ub (priv->bg_color.red,
3043                                 priv->bg_color.green,
3044                                 priv->bg_color.blue,
3045                                 real_alpha);
3046
3047       cogl_rectangle (0, 0, width, height);
3048     }
3049
3050   for (iter = priv->first_child;
3051        iter != NULL;
3052        iter = iter->priv->next_sibling)
3053     {
3054       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3055                     _clutter_actor_get_debug_name (iter),
3056                     _clutter_actor_get_debug_name (actor),
3057                     iter->priv->allocation.x1,
3058                     iter->priv->allocation.y1,
3059                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3060                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3061
3062       clutter_actor_paint (iter);
3063     }
3064 }
3065
3066 /**
3067  * clutter_actor_paint:
3068  * @self: A #ClutterActor
3069  *
3070  * Renders the actor to display.
3071  *
3072  * This function should not be called directly by applications.
3073  * Call clutter_actor_queue_redraw() to queue paints, instead.
3074  *
3075  * This function is context-aware, and will either cause a
3076  * regular paint or a pick paint.
3077  *
3078  * This function will emit the #ClutterActor::paint signal or
3079  * the #ClutterActor::pick signal, depending on the context.
3080  *
3081  * This function does not paint the actor if the actor is set to 0,
3082  * unless it is performing a pick paint.
3083  */
3084 void
3085 clutter_actor_paint (ClutterActor *self)
3086 {
3087   ClutterActorPrivate *priv;
3088   ClutterPickMode pick_mode;
3089   gboolean clip_set = FALSE;
3090   gboolean shader_applied = FALSE;
3091
3092   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3093                           "Actor real-paint counter",
3094                           "Increments each time any actor is painted",
3095                           0 /* no application private data */);
3096   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3097                           "Actor pick-paint counter",
3098                           "Increments each time any actor is painted "
3099                           "for picking",
3100                           0 /* no application private data */);
3101
3102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3103
3104   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3105     return;
3106
3107   priv = self->priv;
3108
3109   pick_mode = _clutter_context_get_pick_mode ();
3110
3111   if (pick_mode == CLUTTER_PICK_NONE)
3112     priv->propagated_one_redraw = FALSE;
3113
3114   /* It's an important optimization that we consider painting of
3115    * actors with 0 opacity to be a NOP... */
3116   if (pick_mode == CLUTTER_PICK_NONE &&
3117       /* ignore top-levels, since they might be transparent */
3118       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3119       /* Use the override opacity if its been set */
3120       ((priv->opacity_override >= 0) ?
3121        priv->opacity_override : priv->opacity) == 0)
3122     return;
3123
3124   /* if we aren't paintable (not in a toplevel with all
3125    * parents paintable) then do nothing.
3126    */
3127   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3128     return;
3129
3130   /* mark that we are in the paint process */
3131   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3132
3133   cogl_push_matrix();
3134
3135   if (priv->enable_model_view_transform)
3136     {
3137       CoglMatrix matrix;
3138
3139       /* XXX: It could be better to cache the modelview with the actor
3140        * instead of progressively building up the transformations on
3141        * the matrix stack every time we paint. */
3142       cogl_get_modelview_matrix (&matrix);
3143       _clutter_actor_apply_modelview_transform (self, &matrix);
3144
3145 #ifdef CLUTTER_ENABLE_DEBUG
3146       /* Catch when out-of-band transforms have been made by actors not as part
3147        * of an apply_transform vfunc... */
3148       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3149         {
3150           CoglMatrix expected_matrix;
3151
3152           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3153                                                              &expected_matrix);
3154
3155           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3156             {
3157               GString *buf = g_string_sized_new (1024);
3158               ClutterActor *parent;
3159
3160               parent = self;
3161               while (parent != NULL)
3162                 {
3163                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3164
3165                   if (parent->priv->parent != NULL)
3166                     g_string_append (buf, "->");
3167
3168                   parent = parent->priv->parent;
3169                 }
3170
3171               g_warning ("Unexpected transform found when painting actor "
3172                          "\"%s\". This will be caused by one of the actor's "
3173                          "ancestors (%s) using the Cogl API directly to transform "
3174                          "children instead of using ::apply_transform().",
3175                          _clutter_actor_get_debug_name (self),
3176                          buf->str);
3177
3178               g_string_free (buf, TRUE);
3179             }
3180         }
3181 #endif /* CLUTTER_ENABLE_DEBUG */
3182
3183       cogl_set_modelview_matrix (&matrix);
3184     }
3185
3186   if (priv->has_clip)
3187     {
3188       cogl_clip_push_rectangle (priv->clip.x,
3189                                 priv->clip.y,
3190                                 priv->clip.x + priv->clip.width,
3191                                 priv->clip.y + priv->clip.height);
3192       clip_set = TRUE;
3193     }
3194   else if (priv->clip_to_allocation)
3195     {
3196       gfloat width, height;
3197
3198       width  = priv->allocation.x2 - priv->allocation.x1;
3199       height = priv->allocation.y2 - priv->allocation.y1;
3200
3201       cogl_clip_push_rectangle (0, 0, width, height);
3202       clip_set = TRUE;
3203     }
3204
3205   if (pick_mode == CLUTTER_PICK_NONE)
3206     {
3207       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3208
3209       /* We check whether we need to add the flatten effect before
3210          each paint so that we can avoid having a mechanism for
3211          applications to notify when the value of the
3212          has_overlaps virtual changes. */
3213       add_or_remove_flatten_effect (self);
3214     }
3215   else
3216     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3217
3218   /* We save the current paint volume so that the next time the
3219    * actor queues a redraw we can constrain the redraw to just
3220    * cover the union of the new bounding box and the old.
3221    *
3222    * We also fetch the current paint volume to perform culling so
3223    * we can avoid painting actors outside the current clip region.
3224    *
3225    * If we are painting inside a clone, we should neither update
3226    * the paint volume or use it to cull painting, since the paint
3227    * box represents the location of the source actor on the
3228    * screen.
3229    *
3230    * XXX: We are starting to do a lot of vertex transforms on
3231    * the CPU in a typical paint, so at some point we should
3232    * audit these and consider caching some things.
3233    *
3234    * NB: We don't perform culling while picking at this point because
3235    * clutter-stage.c doesn't setup the clipping planes appropriately.
3236    *
3237    * NB: We don't want to update the last-paint-volume during picking
3238    * because the last-paint-volume is used to determine the old screen
3239    * space location of an actor that has moved so we can know the
3240    * minimal region to redraw to clear an old view of the actor. If we
3241    * update this during picking then by the time we come around to
3242    * paint then the last-paint-volume would likely represent the new
3243    * actor position not the old.
3244    */
3245   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3246     {
3247       gboolean success;
3248       /* annoyingly gcc warns if uninitialized even though
3249        * the initialization is redundant :-( */
3250       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3251
3252       if (G_LIKELY ((clutter_paint_debug_flags &
3253                      (CLUTTER_DEBUG_DISABLE_CULLING |
3254                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3255                     (CLUTTER_DEBUG_DISABLE_CULLING |
3256                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3257         _clutter_actor_update_last_paint_volume (self);
3258
3259       success = cull_actor (self, &result);
3260
3261       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3262         _clutter_actor_paint_cull_result (self, success, result);
3263       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3264         goto done;
3265     }
3266
3267   if (priv->effects == NULL)
3268     {
3269       if (pick_mode == CLUTTER_PICK_NONE &&
3270           actor_has_shader_data (self))
3271         {
3272           _clutter_actor_shader_pre_paint (self, FALSE);
3273           shader_applied = TRUE;
3274         }
3275
3276       priv->next_effect_to_paint = NULL;
3277     }
3278   else
3279     priv->next_effect_to_paint =
3280       _clutter_meta_group_peek_metas (priv->effects);
3281
3282   clutter_actor_continue_paint (self);
3283
3284   if (shader_applied)
3285     _clutter_actor_shader_post_paint (self);
3286
3287   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3288                   pick_mode == CLUTTER_PICK_NONE))
3289     _clutter_actor_draw_paint_volume (self);
3290
3291 done:
3292   /* If we make it here then the actor has run through a complete
3293      paint run including all the effects so it's no longer dirty */
3294   if (pick_mode == CLUTTER_PICK_NONE)
3295     priv->is_dirty = FALSE;
3296
3297   if (clip_set)
3298     cogl_clip_pop();
3299
3300   cogl_pop_matrix();
3301
3302   /* paint sequence complete */
3303   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3304 }
3305
3306 /**
3307  * clutter_actor_continue_paint:
3308  * @self: A #ClutterActor
3309  *
3310  * Run the next stage of the paint sequence. This function should only
3311  * be called within the implementation of the ‘run’ virtual of a
3312  * #ClutterEffect. It will cause the run method of the next effect to
3313  * be applied, or it will paint the actual actor if the current effect
3314  * is the last effect in the chain.
3315  *
3316  * Since: 1.8
3317  */
3318 void
3319 clutter_actor_continue_paint (ClutterActor *self)
3320 {
3321   ClutterActorPrivate *priv;
3322
3323   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3324   /* This should only be called from with in the ‘run’ implementation
3325      of a ClutterEffect */
3326   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3327
3328   priv = self->priv;
3329
3330   /* Skip any effects that are disabled */
3331   while (priv->next_effect_to_paint &&
3332          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3333     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3334
3335   /* If this has come from the last effect then we'll just paint the
3336      actual actor */
3337   if (priv->next_effect_to_paint == NULL)
3338     {
3339       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3340         {
3341           g_signal_emit (self, actor_signals[PAINT], 0);
3342         }
3343       else
3344         {
3345           ClutterColor col = { 0, };
3346
3347           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3348
3349           /* Actor will then paint silhouette of itself in supplied
3350            * color.  See clutter_stage_get_actor_at_pos() for where
3351            * picking is enabled.
3352            */
3353           g_signal_emit (self, actor_signals[PICK], 0, &col);
3354         }
3355     }
3356   else
3357     {
3358       ClutterEffect *old_current_effect;
3359       ClutterEffectPaintFlags run_flags = 0;
3360
3361       /* Cache the current effect so that we can put it back before
3362          returning */
3363       old_current_effect = priv->current_effect;
3364
3365       priv->current_effect = priv->next_effect_to_paint->data;
3366       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3367
3368       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3369         {
3370           if (priv->is_dirty)
3371             {
3372               /* If there's an effect queued with this redraw then all
3373                  effects up to that one will be considered dirty. It
3374                  is expected the queued effect will paint the cached
3375                  image and not call clutter_actor_continue_paint again
3376                  (although it should work ok if it does) */
3377               if (priv->effect_to_redraw == NULL ||
3378                   priv->current_effect != priv->effect_to_redraw)
3379                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3380             }
3381
3382           _clutter_effect_paint (priv->current_effect, run_flags);
3383         }
3384       else
3385         {
3386           /* We can't determine when an actor has been modified since
3387              its last pick so lets just assume it has always been
3388              modified */
3389           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3390
3391           _clutter_effect_pick (priv->current_effect, run_flags);
3392         }
3393
3394       priv->current_effect = old_current_effect;
3395     }
3396 }
3397
3398 static ClutterActorTraverseVisitFlags
3399 invalidate_queue_redraw_entry (ClutterActor *self,
3400                                int           depth,
3401                                gpointer      user_data)
3402 {
3403   ClutterActorPrivate *priv = self->priv;
3404
3405   if (priv->queue_redraw_entry != NULL)
3406     {
3407       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3408       priv->queue_redraw_entry = NULL;
3409     }
3410
3411   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3412 }
3413
3414 static inline void
3415 remove_child (ClutterActor *self,
3416               ClutterActor *child)
3417 {
3418   ClutterActor *prev_sibling, *next_sibling;
3419
3420   prev_sibling = child->priv->prev_sibling;
3421   next_sibling = child->priv->next_sibling;
3422
3423   if (prev_sibling != NULL)
3424     prev_sibling->priv->next_sibling = next_sibling;
3425
3426   if (next_sibling != NULL)
3427     next_sibling->priv->prev_sibling = prev_sibling;
3428
3429   if (self->priv->first_child == child)
3430     self->priv->first_child = next_sibling;
3431
3432   if (self->priv->last_child == child)
3433     self->priv->last_child = prev_sibling;
3434
3435   child->priv->parent = NULL;
3436   child->priv->prev_sibling = NULL;
3437   child->priv->next_sibling = NULL;
3438 }
3439
3440 typedef enum {
3441   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3442   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3443   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3444   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3445   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3446   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3447
3448   /* default flags for public API */
3449   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3450                                     REMOVE_CHILD_EMIT_PARENT_SET |
3451                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3452                                     REMOVE_CHILD_CHECK_STATE |
3453                                     REMOVE_CHILD_FLUSH_QUEUE |
3454                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3455
3456   /* flags for legacy/deprecated API */
3457   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_EMIT_PARENT_SET |
3460                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3461 } ClutterActorRemoveChildFlags;
3462
3463 /*< private >
3464  * clutter_actor_remove_child_internal:
3465  * @self: a #ClutterActor
3466  * @child: the child of @self that has to be removed
3467  * @flags: control the removal operations
3468  *
3469  * Removes @child from the list of children of @self.
3470  */
3471 static void
3472 clutter_actor_remove_child_internal (ClutterActor                 *self,
3473                                      ClutterActor                 *child,
3474                                      ClutterActorRemoveChildFlags  flags)
3475 {
3476   ClutterActor *old_first, *old_last;
3477   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3478   gboolean flush_queue;
3479   gboolean notify_first_last;
3480   gboolean was_mapped;
3481
3482   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3483   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3484   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3485   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3486   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3487   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3488
3489   if (destroy_meta)
3490     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3491
3492   if (check_state)
3493     {
3494       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3495
3496       /* we need to unrealize *before* we set parent_actor to NULL,
3497        * because in an unrealize method actors are dissociating from the
3498        * stage, which means they need to be able to
3499        * clutter_actor_get_stage().
3500        *
3501        * yhis should unmap and unrealize, unless we're reparenting.
3502        */
3503       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3504     }
3505   else
3506     was_mapped = FALSE;
3507
3508   if (flush_queue)
3509     {
3510       /* We take this opportunity to invalidate any queue redraw entry
3511        * associated with the actor and descendants since we won't be able to
3512        * determine the appropriate stage after this.
3513        *
3514        * we do this after we updated the mapped state because actors might
3515        * end up queueing redraws inside their mapped/unmapped virtual
3516        * functions, and if we invalidate the redraw entry we could end up
3517        * with an inconsistent state and weird memory corruption. see
3518        * bugs:
3519        *
3520        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3521        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3522        */
3523       _clutter_actor_traverse (child,
3524                                0,
3525                                invalidate_queue_redraw_entry,
3526                                NULL,
3527                                NULL);
3528     }
3529
3530   old_first = self->priv->first_child;
3531   old_last = self->priv->last_child;
3532
3533   remove_child (self, child);
3534
3535   self->priv->n_children -= 1;
3536
3537   self->priv->age += 1;
3538
3539   /* clutter_actor_reparent() will emit ::parent-set for us */
3540   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3541     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3542
3543   /* if the child was mapped then we need to relayout ourselves to account
3544    * for the removed child
3545    */
3546   if (was_mapped)
3547     clutter_actor_queue_relayout (self);
3548
3549   /* we need to emit the signal before dropping the reference */
3550   if (emit_actor_removed)
3551     g_signal_emit_by_name (self, "actor-removed", child);
3552
3553   if (notify_first_last)
3554     {
3555       if (old_first != self->priv->first_child)
3556         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3557
3558       if (old_last != self->priv->last_child)
3559         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3560     }
3561
3562   /* remove the reference we acquired in clutter_actor_add_child() */
3563   g_object_unref (child);
3564 }
3565
3566 static const ClutterTransformInfo default_transform_info = {
3567   0.0, { 0, },          /* rotation-x */
3568   0.0, { 0, },          /* rotation-y */
3569   0.0, { 0, },          /* rotation-z */
3570
3571   1.0, 1.0, { 0, },     /* scale */
3572
3573   { 0, },               /* anchor */
3574 };
3575
3576 /*< private >
3577  * _clutter_actor_get_transform_info_or_defaults:
3578  * @self: a #ClutterActor
3579  *
3580  * Retrieves the ClutterTransformInfo structure associated to an actor.
3581  *
3582  * If the actor does not have a ClutterTransformInfo structure associated
3583  * to it, then the default structure will be returned.
3584  *
3585  * This function should only be used for getters.
3586  *
3587  * Return value: a const pointer to the ClutterTransformInfo structure
3588  */
3589 const ClutterTransformInfo *
3590 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3591 {
3592   ClutterTransformInfo *info;
3593
3594   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3595   if (info != NULL)
3596     return info;
3597
3598   return &default_transform_info;
3599 }
3600
3601 static void
3602 clutter_transform_info_free (gpointer data)
3603 {
3604   if (data != NULL)
3605     g_slice_free (ClutterTransformInfo, data);
3606 }
3607
3608 /*< private >
3609  * _clutter_actor_get_transform_info:
3610  * @self: a #ClutterActor
3611  *
3612  * Retrieves a pointer to the ClutterTransformInfo structure.
3613  *
3614  * If the actor does not have a ClutterTransformInfo associated to it, one
3615  * will be created and initialized to the default values.
3616  *
3617  * This function should be used for setters.
3618  *
3619  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3620  * instead.
3621  *
3622  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3623  *   structure
3624  */
3625 ClutterTransformInfo *
3626 _clutter_actor_get_transform_info (ClutterActor *self)
3627 {
3628   ClutterTransformInfo *info;
3629
3630   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3631   if (info == NULL)
3632     {
3633       info = g_slice_new (ClutterTransformInfo);
3634
3635       *info = default_transform_info;
3636
3637       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3638                                info,
3639                                clutter_transform_info_free);
3640     }
3641
3642   return info;
3643 }
3644
3645 /*< private >
3646  * clutter_actor_set_rotation_angle_internal:
3647  * @self: a #ClutterActor
3648  * @axis: the axis of the angle to change
3649  * @angle: the angle of rotation
3650  *
3651  * Sets the rotation angle on the given axis without affecting the
3652  * rotation center point.
3653  */
3654 static inline void
3655 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3656                                            ClutterRotateAxis  axis,
3657                                            gdouble            angle)
3658 {
3659   GObject *obj = G_OBJECT (self);
3660   ClutterTransformInfo *info;
3661
3662   info = _clutter_actor_get_transform_info (self);
3663
3664   g_object_freeze_notify (obj);
3665
3666   switch (axis)
3667     {
3668     case CLUTTER_X_AXIS:
3669       info->rx_angle = angle;
3670       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3671       break;
3672
3673     case CLUTTER_Y_AXIS:
3674       info->ry_angle = angle;
3675       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3676       break;
3677
3678     case CLUTTER_Z_AXIS:
3679       info->rz_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3681       break;
3682     }
3683
3684   self->priv->transform_valid = FALSE;
3685
3686   g_object_thaw_notify (obj);
3687
3688   clutter_actor_queue_redraw (self);
3689 }
3690
3691 /*< private >
3692  * clutter_actor_set_rotation_center_internal:
3693  * @self: a #ClutterActor
3694  * @axis: the axis of the center to change
3695  * @center: the coordinates of the rotation center
3696  *
3697  * Sets the rotation center on the given axis without affecting the
3698  * rotation angle.
3699  */
3700 static inline void
3701 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3702                                             ClutterRotateAxis    axis,
3703                                             const ClutterVertex *center)
3704 {
3705   GObject *obj = G_OBJECT (self);
3706   ClutterTransformInfo *info;
3707   ClutterVertex v = { 0, 0, 0 };
3708
3709   info = _clutter_actor_get_transform_info (self);
3710
3711   if (center != NULL)
3712     v = *center;
3713
3714   g_object_freeze_notify (obj);
3715
3716   switch (axis)
3717     {
3718     case CLUTTER_X_AXIS:
3719       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3720       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3721       break;
3722
3723     case CLUTTER_Y_AXIS:
3724       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3725       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3726       break;
3727
3728     case CLUTTER_Z_AXIS:
3729       /* if the previously set rotation center was fractional, then
3730        * setting explicit coordinates will have to notify the
3731        * :rotation-center-z-gravity property as well
3732        */
3733       if (info->rz_center.is_fractional)
3734         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3735
3736       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3737       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3738       break;
3739     }
3740
3741   self->priv->transform_valid = FALSE;
3742
3743   g_object_thaw_notify (obj);
3744
3745   clutter_actor_queue_redraw (self);
3746 }
3747
3748 static inline void
3749 clutter_actor_set_scale_factor (ClutterActor      *self,
3750                                 ClutterRotateAxis  axis,
3751                                 gdouble            factor)
3752 {
3753   GObject *obj = G_OBJECT (self);
3754   ClutterTransformInfo *info;
3755
3756   info = _clutter_actor_get_transform_info (self);
3757
3758   g_object_freeze_notify (obj);
3759
3760   switch (axis)
3761     {
3762     case CLUTTER_X_AXIS:
3763       info->scale_x = factor;
3764       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3765       break;
3766
3767     case CLUTTER_Y_AXIS:
3768       info->scale_y = factor;
3769       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3770       break;
3771
3772     default:
3773       g_assert_not_reached ();
3774     }
3775
3776   self->priv->transform_valid = FALSE;
3777
3778   clutter_actor_queue_redraw (self);
3779
3780   g_object_thaw_notify (obj);
3781 }
3782
3783 static inline void
3784 clutter_actor_set_scale_center (ClutterActor      *self,
3785                                 ClutterRotateAxis  axis,
3786                                 gfloat             coord)
3787 {
3788   GObject *obj = G_OBJECT (self);
3789   ClutterTransformInfo *info;
3790   gfloat center_x, center_y;
3791
3792   info = _clutter_actor_get_transform_info (self);
3793
3794   g_object_freeze_notify (obj);
3795
3796   /* get the current scale center coordinates */
3797   clutter_anchor_coord_get_units (self, &info->scale_center,
3798                                   &center_x,
3799                                   &center_y,
3800                                   NULL);
3801
3802   /* we need to notify this too, because setting explicit coordinates will
3803    * change the gravity as a side effect
3804    */
3805   if (info->scale_center.is_fractional)
3806     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3807
3808   switch (axis)
3809     {
3810     case CLUTTER_X_AXIS:
3811       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3812       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3813       break;
3814
3815     case CLUTTER_Y_AXIS:
3816       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3817       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3818       break;
3819
3820     default:
3821       g_assert_not_reached ();
3822     }
3823
3824   self->priv->transform_valid = FALSE;
3825
3826   clutter_actor_queue_redraw (self);
3827
3828   g_object_thaw_notify (obj);
3829 }
3830
3831 static inline void
3832 clutter_actor_set_anchor_coord (ClutterActor      *self,
3833                                 ClutterRotateAxis  axis,
3834                                 gfloat             coord)
3835 {
3836   GObject *obj = G_OBJECT (self);
3837   ClutterTransformInfo *info;
3838   gfloat anchor_x, anchor_y;
3839
3840   info = _clutter_actor_get_transform_info (self);
3841
3842   g_object_freeze_notify (obj);
3843
3844   clutter_anchor_coord_get_units (self, &info->anchor,
3845                                   &anchor_x,
3846                                   &anchor_y,
3847                                   NULL);
3848
3849   if (info->anchor.is_fractional)
3850     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3851
3852   switch (axis)
3853     {
3854     case CLUTTER_X_AXIS:
3855       clutter_anchor_coord_set_units (&info->anchor,
3856                                       coord,
3857                                       anchor_y,
3858                                       0.0);
3859       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3860       break;
3861
3862     case CLUTTER_Y_AXIS:
3863       clutter_anchor_coord_set_units (&info->anchor,
3864                                       anchor_x,
3865                                       coord,
3866                                       0.0);
3867       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3868       break;
3869
3870     default:
3871       g_assert_not_reached ();
3872     }
3873
3874   self->priv->transform_valid = FALSE;
3875
3876   clutter_actor_queue_redraw (self);
3877
3878   g_object_thaw_notify (obj);
3879 }
3880
3881 static void
3882 clutter_actor_set_property (GObject      *object,
3883                             guint         prop_id,
3884                             const GValue *value,
3885                             GParamSpec   *pspec)
3886 {
3887   ClutterActor *actor = CLUTTER_ACTOR (object);
3888   ClutterActorPrivate *priv = actor->priv;
3889
3890   switch (prop_id)
3891     {
3892     case PROP_X:
3893       clutter_actor_set_x (actor, g_value_get_float (value));
3894       break;
3895
3896     case PROP_Y:
3897       clutter_actor_set_y (actor, g_value_get_float (value));
3898       break;
3899
3900     case PROP_WIDTH:
3901       clutter_actor_set_width (actor, g_value_get_float (value));
3902       break;
3903
3904     case PROP_HEIGHT:
3905       clutter_actor_set_height (actor, g_value_get_float (value));
3906       break;
3907
3908     case PROP_FIXED_X:
3909       clutter_actor_set_x (actor, g_value_get_float (value));
3910       break;
3911
3912     case PROP_FIXED_Y:
3913       clutter_actor_set_y (actor, g_value_get_float (value));
3914       break;
3915
3916     case PROP_FIXED_POSITION_SET:
3917       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3918       break;
3919
3920     case PROP_MIN_WIDTH:
3921       clutter_actor_set_min_width (actor, g_value_get_float (value));
3922       break;
3923
3924     case PROP_MIN_HEIGHT:
3925       clutter_actor_set_min_height (actor, g_value_get_float (value));
3926       break;
3927
3928     case PROP_NATURAL_WIDTH:
3929       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3930       break;
3931
3932     case PROP_NATURAL_HEIGHT:
3933       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3934       break;
3935
3936     case PROP_MIN_WIDTH_SET:
3937       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3938       break;
3939
3940     case PROP_MIN_HEIGHT_SET:
3941       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3942       break;
3943
3944     case PROP_NATURAL_WIDTH_SET:
3945       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3946       break;
3947
3948     case PROP_NATURAL_HEIGHT_SET:
3949       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3950       break;
3951
3952     case PROP_REQUEST_MODE:
3953       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3954       break;
3955
3956     case PROP_DEPTH:
3957       clutter_actor_set_depth (actor, g_value_get_float (value));
3958       break;
3959
3960     case PROP_OPACITY:
3961       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3962       break;
3963
3964     case PROP_OFFSCREEN_REDIRECT:
3965       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3966       break;
3967
3968     case PROP_NAME:
3969       clutter_actor_set_name (actor, g_value_get_string (value));
3970       break;
3971
3972     case PROP_VISIBLE:
3973       if (g_value_get_boolean (value) == TRUE)
3974         clutter_actor_show (actor);
3975       else
3976         clutter_actor_hide (actor);
3977       break;
3978
3979     case PROP_SCALE_X:
3980       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3981                                       g_value_get_double (value));
3982       break;
3983
3984     case PROP_SCALE_Y:
3985       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3986                                       g_value_get_double (value));
3987       break;
3988
3989     case PROP_SCALE_CENTER_X:
3990       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
3991                                       g_value_get_float (value));
3992       break;
3993
3994     case PROP_SCALE_CENTER_Y:
3995       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
3996                                       g_value_get_float (value));
3997       break;
3998
3999     case PROP_SCALE_GRAVITY:
4000       {
4001         const ClutterTransformInfo *info;
4002         ClutterGravity gravity;
4003
4004         info = _clutter_actor_get_transform_info_or_defaults (actor);
4005         gravity = g_value_get_enum (value);
4006
4007         clutter_actor_set_scale_with_gravity (actor,
4008                                               info->scale_x,
4009                                               info->scale_y,
4010                                               gravity);
4011       }
4012       break;
4013
4014     case PROP_CLIP:
4015       {
4016         const ClutterGeometry *geom = g_value_get_boxed (value);
4017
4018         clutter_actor_set_clip (actor,
4019                                 geom->x, geom->y,
4020                                 geom->width, geom->height);
4021       }
4022       break;
4023
4024     case PROP_CLIP_TO_ALLOCATION:
4025       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4026       break;
4027
4028     case PROP_REACTIVE:
4029       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4030       break;
4031
4032     case PROP_ROTATION_ANGLE_X:
4033       clutter_actor_set_rotation_angle_internal (actor,
4034                                                  CLUTTER_X_AXIS,
4035                                                  g_value_get_double (value));
4036       break;
4037
4038     case PROP_ROTATION_ANGLE_Y:
4039       clutter_actor_set_rotation_angle_internal (actor,
4040                                                  CLUTTER_Y_AXIS,
4041                                                  g_value_get_double (value));
4042       break;
4043
4044     case PROP_ROTATION_ANGLE_Z:
4045       clutter_actor_set_rotation_angle_internal (actor,
4046                                                  CLUTTER_Z_AXIS,
4047                                                  g_value_get_double (value));
4048       break;
4049
4050     case PROP_ROTATION_CENTER_X:
4051       clutter_actor_set_rotation_center_internal (actor,
4052                                                   CLUTTER_X_AXIS,
4053                                                   g_value_get_boxed (value));
4054       break;
4055
4056     case PROP_ROTATION_CENTER_Y:
4057       clutter_actor_set_rotation_center_internal (actor,
4058                                                   CLUTTER_Y_AXIS,
4059                                                   g_value_get_boxed (value));
4060       break;
4061
4062     case PROP_ROTATION_CENTER_Z:
4063       clutter_actor_set_rotation_center_internal (actor,
4064                                                   CLUTTER_Z_AXIS,
4065                                                   g_value_get_boxed (value));
4066       break;
4067
4068     case PROP_ROTATION_CENTER_Z_GRAVITY:
4069       {
4070         const ClutterTransformInfo *info;
4071
4072         info = _clutter_actor_get_transform_info_or_defaults (actor);
4073         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4074                                                    g_value_get_enum (value));
4075       }
4076       break;
4077
4078     case PROP_ANCHOR_X:
4079       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4080                                       g_value_get_float (value));
4081       break;
4082
4083     case PROP_ANCHOR_Y:
4084       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4085                                       g_value_get_float (value));
4086       break;
4087
4088     case PROP_ANCHOR_GRAVITY:
4089       clutter_actor_set_anchor_point_from_gravity (actor,
4090                                                    g_value_get_enum (value));
4091       break;
4092
4093     case PROP_SHOW_ON_SET_PARENT:
4094       priv->show_on_set_parent = g_value_get_boolean (value);
4095       break;
4096
4097     case PROP_TEXT_DIRECTION:
4098       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4099       break;
4100
4101     case PROP_ACTIONS:
4102       clutter_actor_add_action (actor, g_value_get_object (value));
4103       break;
4104
4105     case PROP_CONSTRAINTS:
4106       clutter_actor_add_constraint (actor, g_value_get_object (value));
4107       break;
4108
4109     case PROP_EFFECT:
4110       clutter_actor_add_effect (actor, g_value_get_object (value));
4111       break;
4112
4113     case PROP_LAYOUT_MANAGER:
4114       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4115       break;
4116
4117     case PROP_X_ALIGN:
4118       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4119       break;
4120
4121     case PROP_Y_ALIGN:
4122       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4123       break;
4124
4125     case PROP_MARGIN_TOP:
4126       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4127       break;
4128
4129     case PROP_MARGIN_BOTTOM:
4130       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4131       break;
4132
4133     case PROP_MARGIN_LEFT:
4134       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4135       break;
4136
4137     case PROP_MARGIN_RIGHT:
4138       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4139       break;
4140
4141     case PROP_BACKGROUND_COLOR:
4142       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4143       break;
4144
4145     default:
4146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4147       break;
4148     }
4149 }
4150
4151 static void
4152 clutter_actor_get_property (GObject    *object,
4153                             guint       prop_id,
4154                             GValue     *value,
4155                             GParamSpec *pspec)
4156 {
4157   ClutterActor *actor = CLUTTER_ACTOR (object);
4158   ClutterActorPrivate *priv = actor->priv;
4159
4160   switch (prop_id)
4161     {
4162     case PROP_X:
4163       g_value_set_float (value, clutter_actor_get_x (actor));
4164       break;
4165
4166     case PROP_Y:
4167       g_value_set_float (value, clutter_actor_get_y (actor));
4168       break;
4169
4170     case PROP_WIDTH:
4171       g_value_set_float (value, clutter_actor_get_width (actor));
4172       break;
4173
4174     case PROP_HEIGHT:
4175       g_value_set_float (value, clutter_actor_get_height (actor));
4176       break;
4177
4178     case PROP_FIXED_X:
4179       {
4180         const ClutterLayoutInfo *info;
4181
4182         info = _clutter_actor_get_layout_info_or_defaults (actor);
4183         g_value_set_float (value, info->fixed_x);
4184       }
4185       break;
4186
4187     case PROP_FIXED_Y:
4188       {
4189         const ClutterLayoutInfo *info;
4190
4191         info = _clutter_actor_get_layout_info_or_defaults (actor);
4192         g_value_set_float (value, info->fixed_y);
4193       }
4194       break;
4195
4196     case PROP_FIXED_POSITION_SET:
4197       g_value_set_boolean (value, priv->position_set);
4198       break;
4199
4200     case PROP_MIN_WIDTH:
4201       {
4202         const ClutterLayoutInfo *info;
4203
4204         info = _clutter_actor_get_layout_info_or_defaults (actor);
4205         g_value_set_float (value, info->min_width);
4206       }
4207       break;
4208
4209     case PROP_MIN_HEIGHT:
4210       {
4211         const ClutterLayoutInfo *info;
4212
4213         info = _clutter_actor_get_layout_info_or_defaults (actor);
4214         g_value_set_float (value, info->min_height);
4215       }
4216       break;
4217
4218     case PROP_NATURAL_WIDTH:
4219       {
4220         const ClutterLayoutInfo *info;
4221
4222         info = _clutter_actor_get_layout_info_or_defaults (actor);
4223         g_value_set_float (value, info->natural_width);
4224       }
4225       break;
4226
4227     case PROP_NATURAL_HEIGHT:
4228       {
4229         const ClutterLayoutInfo *info;
4230
4231         info = _clutter_actor_get_layout_info_or_defaults (actor);
4232         g_value_set_float (value, info->natural_height);
4233       }
4234       break;
4235
4236     case PROP_MIN_WIDTH_SET:
4237       g_value_set_boolean (value, priv->min_width_set);
4238       break;
4239
4240     case PROP_MIN_HEIGHT_SET:
4241       g_value_set_boolean (value, priv->min_height_set);
4242       break;
4243
4244     case PROP_NATURAL_WIDTH_SET:
4245       g_value_set_boolean (value, priv->natural_width_set);
4246       break;
4247
4248     case PROP_NATURAL_HEIGHT_SET:
4249       g_value_set_boolean (value, priv->natural_height_set);
4250       break;
4251
4252     case PROP_REQUEST_MODE:
4253       g_value_set_enum (value, priv->request_mode);
4254       break;
4255
4256     case PROP_ALLOCATION:
4257       g_value_set_boxed (value, &priv->allocation);
4258       break;
4259
4260     case PROP_DEPTH:
4261       g_value_set_float (value, clutter_actor_get_depth (actor));
4262       break;
4263
4264     case PROP_OPACITY:
4265       g_value_set_uint (value, priv->opacity);
4266       break;
4267
4268     case PROP_OFFSCREEN_REDIRECT:
4269       g_value_set_enum (value, priv->offscreen_redirect);
4270       break;
4271
4272     case PROP_NAME:
4273       g_value_set_string (value, priv->name);
4274       break;
4275
4276     case PROP_VISIBLE:
4277       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4278       break;
4279
4280     case PROP_MAPPED:
4281       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4282       break;
4283
4284     case PROP_REALIZED:
4285       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4286       break;
4287
4288     case PROP_HAS_CLIP:
4289       g_value_set_boolean (value, priv->has_clip);
4290       break;
4291
4292     case PROP_CLIP:
4293       {
4294         ClutterGeometry clip;
4295
4296         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4297         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4298         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4299         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4300
4301         g_value_set_boxed (value, &clip);
4302       }
4303       break;
4304
4305     case PROP_CLIP_TO_ALLOCATION:
4306       g_value_set_boolean (value, priv->clip_to_allocation);
4307       break;
4308
4309     case PROP_SCALE_X:
4310       {
4311         const ClutterTransformInfo *info;
4312
4313         info = _clutter_actor_get_transform_info_or_defaults (actor);
4314         g_value_set_double (value, info->scale_x);
4315       }
4316       break;
4317
4318     case PROP_SCALE_Y:
4319       {
4320         const ClutterTransformInfo *info;
4321
4322         info = _clutter_actor_get_transform_info_or_defaults (actor);
4323         g_value_set_double (value, info->scale_y);
4324       }
4325       break;
4326
4327     case PROP_SCALE_CENTER_X:
4328       {
4329         gfloat center;
4330
4331         clutter_actor_get_scale_center (actor, &center, NULL);
4332
4333         g_value_set_float (value, center);
4334       }
4335       break;
4336
4337     case PROP_SCALE_CENTER_Y:
4338       {
4339         gfloat center;
4340
4341         clutter_actor_get_scale_center (actor, NULL, &center);
4342
4343         g_value_set_float (value, center);
4344       }
4345       break;
4346
4347     case PROP_SCALE_GRAVITY:
4348       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4349       break;
4350
4351     case PROP_REACTIVE:
4352       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4353       break;
4354
4355     case PROP_ROTATION_ANGLE_X:
4356       {
4357         const ClutterTransformInfo *info;
4358
4359         info = _clutter_actor_get_transform_info_or_defaults (actor);
4360         g_value_set_double (value, info->rx_angle);
4361       }
4362       break;
4363
4364     case PROP_ROTATION_ANGLE_Y:
4365       {
4366         const ClutterTransformInfo *info;
4367
4368         info = _clutter_actor_get_transform_info_or_defaults (actor);
4369         g_value_set_double (value, info->ry_angle);
4370       }
4371       break;
4372
4373     case PROP_ROTATION_ANGLE_Z:
4374       {
4375         const ClutterTransformInfo *info;
4376
4377         info = _clutter_actor_get_transform_info_or_defaults (actor);
4378         g_value_set_double (value, info->rz_angle);
4379       }
4380       break;
4381
4382     case PROP_ROTATION_CENTER_X:
4383       {
4384         ClutterVertex center;
4385
4386         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4387                                     &center.x,
4388                                     &center.y,
4389                                     &center.z);
4390
4391         g_value_set_boxed (value, &center);
4392       }
4393       break;
4394
4395     case PROP_ROTATION_CENTER_Y:
4396       {
4397         ClutterVertex center;
4398
4399         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4400                                     &center.x,
4401                                     &center.y,
4402                                     &center.z);
4403
4404         g_value_set_boxed (value, &center);
4405       }
4406       break;
4407
4408     case PROP_ROTATION_CENTER_Z:
4409       {
4410         ClutterVertex center;
4411
4412         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4413                                     &center.x,
4414                                     &center.y,
4415                                     &center.z);
4416
4417         g_value_set_boxed (value, &center);
4418       }
4419       break;
4420
4421     case PROP_ROTATION_CENTER_Z_GRAVITY:
4422       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4423       break;
4424
4425     case PROP_ANCHOR_X:
4426       {
4427         const ClutterTransformInfo *info;
4428         gfloat anchor_x;
4429
4430         info = _clutter_actor_get_transform_info_or_defaults (actor);
4431         clutter_anchor_coord_get_units (actor, &info->anchor,
4432                                         &anchor_x,
4433                                         NULL,
4434                                         NULL);
4435         g_value_set_float (value, anchor_x);
4436       }
4437       break;
4438
4439     case PROP_ANCHOR_Y:
4440       {
4441         const ClutterTransformInfo *info;
4442         gfloat anchor_y;
4443
4444         info = _clutter_actor_get_transform_info_or_defaults (actor);
4445         clutter_anchor_coord_get_units (actor, &info->anchor,
4446                                         NULL,
4447                                         &anchor_y,
4448                                         NULL);
4449         g_value_set_float (value, anchor_y);
4450       }
4451       break;
4452
4453     case PROP_ANCHOR_GRAVITY:
4454       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4455       break;
4456
4457     case PROP_SHOW_ON_SET_PARENT:
4458       g_value_set_boolean (value, priv->show_on_set_parent);
4459       break;
4460
4461     case PROP_TEXT_DIRECTION:
4462       g_value_set_enum (value, priv->text_direction);
4463       break;
4464
4465     case PROP_HAS_POINTER:
4466       g_value_set_boolean (value, priv->has_pointer);
4467       break;
4468
4469     case PROP_LAYOUT_MANAGER:
4470       g_value_set_object (value, priv->layout_manager);
4471       break;
4472
4473     case PROP_X_ALIGN:
4474       {
4475         const ClutterLayoutInfo *info;
4476
4477         info = _clutter_actor_get_layout_info_or_defaults (actor);
4478         g_value_set_enum (value, info->x_align);
4479       }
4480       break;
4481
4482     case PROP_Y_ALIGN:
4483       {
4484         const ClutterLayoutInfo *info;
4485
4486         info = _clutter_actor_get_layout_info_or_defaults (actor);
4487         g_value_set_enum (value, info->y_align);
4488       }
4489       break;
4490
4491     case PROP_MARGIN_TOP:
4492       {
4493         const ClutterLayoutInfo *info;
4494
4495         info = _clutter_actor_get_layout_info_or_defaults (actor);
4496         g_value_set_float (value, info->margin.top);
4497       }
4498       break;
4499
4500     case PROP_MARGIN_BOTTOM:
4501       {
4502         const ClutterLayoutInfo *info;
4503
4504         info = _clutter_actor_get_layout_info_or_defaults (actor);
4505         g_value_set_float (value, info->margin.bottom);
4506       }
4507       break;
4508
4509     case PROP_MARGIN_LEFT:
4510       {
4511         const ClutterLayoutInfo *info;
4512
4513         info = _clutter_actor_get_layout_info_or_defaults (actor);
4514         g_value_set_float (value, info->margin.left);
4515       }
4516       break;
4517
4518     case PROP_MARGIN_RIGHT:
4519       {
4520         const ClutterLayoutInfo *info;
4521
4522         info = _clutter_actor_get_layout_info_or_defaults (actor);
4523         g_value_set_float (value, info->margin.right);
4524       }
4525       break;
4526
4527     case PROP_BACKGROUND_COLOR_SET:
4528       g_value_set_boolean (value, priv->bg_color_set);
4529       break;
4530
4531     case PROP_BACKGROUND_COLOR:
4532       g_value_set_boxed (value, &priv->bg_color);
4533       break;
4534
4535     case PROP_FIRST_CHILD:
4536       g_value_set_object (value, priv->first_child);
4537       break;
4538
4539     case PROP_LAST_CHILD:
4540       g_value_set_object (value, priv->last_child);
4541       break;
4542
4543     default:
4544       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4545       break;
4546     }
4547 }
4548
4549 static void
4550 clutter_actor_dispose (GObject *object)
4551 {
4552   ClutterActor *self = CLUTTER_ACTOR (object);
4553   ClutterActorPrivate *priv = self->priv;
4554
4555   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4556                 priv->id,
4557                 g_type_name (G_OBJECT_TYPE (self)),
4558                 object->ref_count);
4559
4560   g_signal_emit (self, actor_signals[DESTROY], 0);
4561
4562   /* avoid recursing when called from clutter_actor_destroy() */
4563   if (priv->parent != NULL)
4564     {
4565       ClutterActor *parent = priv->parent;
4566
4567       /* go through the Container implementation unless this
4568        * is an internal child and has been marked as such.
4569        *
4570        * removing the actor from its parent will reset the
4571        * realized and mapped states.
4572        */
4573       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4574         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4575       else
4576         clutter_actor_remove_child_internal (parent, self,
4577                                              REMOVE_CHILD_LEGACY_FLAGS);
4578     }
4579
4580   /* parent must be gone at this point */
4581   g_assert (priv->parent == NULL);
4582
4583   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4584     {
4585       /* can't be mapped or realized with no parent */
4586       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4587       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4588     }
4589
4590   g_clear_object (&priv->pango_context);
4591   g_clear_object (&priv->actions);
4592   g_clear_object (&priv->constraints);
4593   g_clear_object (&priv->effects);
4594   g_clear_object (&priv->flatten_effect);
4595
4596   if (priv->layout_manager != NULL)
4597     {
4598       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4599       g_object_unref (priv->layout_manager);
4600       priv->layout_manager = NULL;
4601     }
4602
4603   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4604 }
4605
4606 static void
4607 clutter_actor_finalize (GObject *object)
4608 {
4609   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4610
4611   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4612                 priv->name != NULL ? priv->name : "<none>",
4613                 priv->id,
4614                 g_type_name (G_OBJECT_TYPE (object)));
4615
4616   _clutter_context_release_id (priv->id);
4617
4618   g_free (priv->name);
4619
4620   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4621 }
4622
4623
4624 /**
4625  * clutter_actor_get_accessible:
4626  * @self: a #ClutterActor
4627  *
4628  * Returns the accessible object that describes the actor to an
4629  * assistive technology.
4630  *
4631  * If no class-specific #AtkObject implementation is available for the
4632  * actor instance in question, it will inherit an #AtkObject
4633  * implementation from the first ancestor class for which such an
4634  * implementation is defined.
4635  *
4636  * The documentation of the <ulink
4637  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4638  * library contains more information about accessible objects and
4639  * their uses.
4640  *
4641  * Returns: (transfer none): the #AtkObject associated with @actor
4642  */
4643 AtkObject *
4644 clutter_actor_get_accessible (ClutterActor *self)
4645 {
4646   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4647
4648   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4649 }
4650
4651 static AtkObject *
4652 clutter_actor_real_get_accessible (ClutterActor *actor)
4653 {
4654   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4655 }
4656
4657 static AtkObject *
4658 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4659 {
4660   AtkObject *accessible;
4661
4662   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4663   if (accessible != NULL)
4664     g_object_ref (accessible);
4665
4666   return accessible;
4667 }
4668
4669 static void
4670 atk_implementor_iface_init (AtkImplementorIface *iface)
4671 {
4672   iface->ref_accessible = _clutter_actor_ref_accessible;
4673 }
4674
4675 static gboolean
4676 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4677                                      ClutterPaintVolume *volume)
4678 {
4679   ClutterActorPrivate *priv = self->priv;
4680   ClutterActor *child;
4681   gboolean res;
4682
4683   /* this is the default return value: we cannot know if a class
4684    * is going to paint outside its allocation, so we take the
4685    * conservative approach.
4686    */
4687   res = FALSE;
4688
4689   /* we start from the allocation */
4690   clutter_paint_volume_set_from_allocation (volume, self);
4691
4692   /* if the actor has a clip set then we have a pretty definite
4693    * size for the paint volume: the actor cannot possibly paint
4694    * outside the clip region.
4695    */
4696   if (priv->clip_to_allocation)
4697     {
4698       /* the allocation has already been set, so we just flip the
4699        * return value
4700        */
4701       res = TRUE;
4702     }
4703   else if (priv->has_clip &&
4704            priv->clip.width >= 0 &&
4705            priv->clip.height >= 0)
4706     {
4707       ClutterVertex origin;
4708
4709       origin.x = priv->clip.x;
4710       origin.y = priv->clip.y;
4711       origin.z = 0;
4712
4713       clutter_paint_volume_set_origin (volume, &origin);
4714       clutter_paint_volume_set_width (volume, priv->clip.width);
4715       clutter_paint_volume_set_height (volume, priv->clip.height);
4716
4717       res = TRUE;
4718     }
4719
4720   /* if we don't have children we just bail out here... */
4721   if (priv->n_children == 0)
4722     return res;
4723
4724   /* ...but if we have children then we ask for their paint volume in
4725    * our coordinates. if any of our children replies that it doesn't
4726    * have a paint volume, we bail out
4727    */
4728   for (child = priv->first_child;
4729        child != NULL;
4730        child = child->priv->next_sibling)
4731     {
4732       const ClutterPaintVolume *child_volume;
4733
4734       child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4735       if (child_volume == NULL)
4736         {
4737           res = FALSE;
4738           break;
4739         }
4740
4741       clutter_paint_volume_union (volume, child_volume);
4742       res = TRUE;
4743     }
4744
4745   return res;
4746 }
4747
4748 static gboolean
4749 clutter_actor_real_has_overlaps (ClutterActor *self)
4750 {
4751   /* By default we'll assume that all actors need an offscreen redirect to get
4752    * the correct opacity. Actors such as ClutterTexture that would never need
4753    * an offscreen redirect can override this to return FALSE. */
4754   return TRUE;
4755 }
4756
4757 static void
4758 clutter_actor_real_destroy (ClutterActor *actor)
4759 {
4760   ClutterActorIter iter;
4761   ClutterActor *child;
4762
4763   clutter_actor_iter_init (&iter, actor);
4764   while (clutter_actor_iter_next (&iter, &child))
4765     {
4766       g_object_ref (child);
4767       clutter_actor_iter_remove (&iter);
4768       clutter_actor_destroy (child);
4769     }
4770 }
4771
4772 static GObject *
4773 clutter_actor_constructor (GType gtype,
4774                            guint n_props,
4775                            GObjectConstructParam *props)
4776 {
4777   GObjectClass *gobject_class;
4778   ClutterActor *self;
4779   GObject *retval;
4780
4781   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4782   retval = gobject_class->constructor (gtype, n_props, props);
4783   self = CLUTTER_ACTOR (retval);
4784
4785   if (self->priv->layout_manager == NULL)
4786     {
4787       ClutterLayoutManager *default_layout;
4788
4789       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4790
4791       default_layout = clutter_fixed_layout_new ();
4792       clutter_actor_set_layout_manager (self, default_layout);
4793     }
4794
4795   return retval;
4796 }
4797
4798 static void
4799 clutter_actor_class_init (ClutterActorClass *klass)
4800 {
4801   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4802
4803   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4804   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4805   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4806
4807   object_class->constructor = clutter_actor_constructor;
4808   object_class->set_property = clutter_actor_set_property;
4809   object_class->get_property = clutter_actor_get_property;
4810   object_class->dispose = clutter_actor_dispose;
4811   object_class->finalize = clutter_actor_finalize;
4812
4813   klass->show = clutter_actor_real_show;
4814   klass->show_all = clutter_actor_show;
4815   klass->hide = clutter_actor_real_hide;
4816   klass->hide_all = clutter_actor_hide;
4817   klass->map = clutter_actor_real_map;
4818   klass->unmap = clutter_actor_real_unmap;
4819   klass->unrealize = clutter_actor_real_unrealize;
4820   klass->pick = clutter_actor_real_pick;
4821   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4822   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4823   klass->allocate = clutter_actor_real_allocate;
4824   klass->queue_redraw = clutter_actor_real_queue_redraw;
4825   klass->queue_relayout = clutter_actor_real_queue_relayout;
4826   klass->apply_transform = clutter_actor_real_apply_transform;
4827   klass->get_accessible = clutter_actor_real_get_accessible;
4828   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4829   klass->has_overlaps = clutter_actor_real_has_overlaps;
4830   klass->paint = clutter_actor_real_paint;
4831   klass->destroy = clutter_actor_real_destroy;
4832
4833   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4834
4835   /**
4836    * ClutterActor:x:
4837    *
4838    * X coordinate of the actor in pixels. If written, forces a fixed
4839    * position for the actor. If read, returns the fixed position if any,
4840    * otherwise the allocation if available, otherwise 0.
4841    */
4842   obj_props[PROP_X] =
4843     g_param_spec_float ("x",
4844                         P_("X coordinate"),
4845                         P_("X coordinate of the actor"),
4846                         -G_MAXFLOAT, G_MAXFLOAT,
4847                         0.0,
4848                         CLUTTER_PARAM_READWRITE);
4849
4850   /**
4851    * ClutterActor:y:
4852    *
4853    * Y coordinate of the actor in pixels. If written, forces a fixed
4854    * position for the actor.  If read, returns the fixed position if
4855    * any, otherwise the allocation if available, otherwise 0.
4856    */
4857   obj_props[PROP_Y] =
4858     g_param_spec_float ("y",
4859                         P_("Y coordinate"),
4860                         P_("Y coordinate of the actor"),
4861                         -G_MAXFLOAT, G_MAXFLOAT,
4862                         0.0,
4863                         CLUTTER_PARAM_READWRITE);
4864
4865   /**
4866    * ClutterActor:width:
4867    *
4868    * Width of the actor (in pixels). If written, forces the minimum and
4869    * natural size request of the actor to the given width. If read, returns
4870    * the allocated width if available, otherwise the width request.
4871    */
4872   obj_props[PROP_WIDTH] =
4873     g_param_spec_float ("width",
4874                         P_("Width"),
4875                         P_("Width of the actor"),
4876                         0.0, G_MAXFLOAT,
4877                         0.0,
4878                         CLUTTER_PARAM_READWRITE);
4879
4880   /**
4881    * ClutterActor:height:
4882    *
4883    * Height of the actor (in pixels).  If written, forces the minimum and
4884    * natural size request of the actor to the given height. If read, returns
4885    * the allocated height if available, otherwise the height request.
4886    */
4887   obj_props[PROP_HEIGHT] =
4888     g_param_spec_float ("height",
4889                         P_("Height"),
4890                         P_("Height of the actor"),
4891                         0.0, G_MAXFLOAT,
4892                         0.0,
4893                         CLUTTER_PARAM_READWRITE);
4894
4895   /**
4896    * ClutterActor:fixed-x:
4897    *
4898    * The fixed X position of the actor in pixels.
4899    *
4900    * Writing this property sets #ClutterActor:fixed-position-set
4901    * property as well, as a side effect
4902    *
4903    * Since: 0.8
4904    */
4905   obj_props[PROP_FIXED_X] =
4906     g_param_spec_float ("fixed-x",
4907                         P_("Fixed X"),
4908                         P_("Forced X position of the actor"),
4909                         -G_MAXFLOAT, G_MAXFLOAT,
4910                         0.0,
4911                         CLUTTER_PARAM_READWRITE);
4912
4913   /**
4914    * ClutterActor:fixed-y:
4915    *
4916    * The fixed Y position of the actor in pixels.
4917    *
4918    * Writing this property sets the #ClutterActor:fixed-position-set
4919    * property as well, as a side effect
4920    *
4921    * Since: 0.8
4922    */
4923   obj_props[PROP_FIXED_Y] =
4924     g_param_spec_float ("fixed-y",
4925                         P_("Fixed Y"),
4926                         P_("Forced Y position of the actor"),
4927                         -G_MAXFLOAT, G_MAXFLOAT,
4928                         0,
4929                         CLUTTER_PARAM_READWRITE);
4930
4931   /**
4932    * ClutterActor:fixed-position-set:
4933    *
4934    * This flag controls whether the #ClutterActor:fixed-x and
4935    * #ClutterActor:fixed-y properties are used
4936    *
4937    * Since: 0.8
4938    */
4939   obj_props[PROP_FIXED_POSITION_SET] =
4940     g_param_spec_boolean ("fixed-position-set",
4941                           P_("Fixed position set"),
4942                           P_("Whether to use fixed positioning for the actor"),
4943                           FALSE,
4944                           CLUTTER_PARAM_READWRITE);
4945
4946   /**
4947    * ClutterActor:min-width:
4948    *
4949    * A forced minimum width request for the actor, in pixels
4950    *
4951    * Writing this property sets the #ClutterActor:min-width-set property
4952    * as well, as a side effect.
4953    *
4954    *This property overrides the usual width request of the actor.
4955    *
4956    * Since: 0.8
4957    */
4958   obj_props[PROP_MIN_WIDTH] =
4959     g_param_spec_float ("min-width",
4960                         P_("Min Width"),
4961                         P_("Forced minimum width request for the actor"),
4962                         0.0, G_MAXFLOAT,
4963                         0.0,
4964                         CLUTTER_PARAM_READWRITE);
4965
4966   /**
4967    * ClutterActor:min-height:
4968    *
4969    * A forced minimum height request for the actor, in pixels
4970    *
4971    * Writing this property sets the #ClutterActor:min-height-set property
4972    * as well, as a side effect. This property overrides the usual height
4973    * request of the actor.
4974    *
4975    * Since: 0.8
4976    */
4977   obj_props[PROP_MIN_HEIGHT] =
4978     g_param_spec_float ("min-height",
4979                         P_("Min Height"),
4980                         P_("Forced minimum height request for the actor"),
4981                         0.0, G_MAXFLOAT,
4982                         0.0,
4983                         CLUTTER_PARAM_READWRITE);
4984
4985   /**
4986    * ClutterActor:natural-width:
4987    *
4988    * A forced natural width request for the actor, in pixels
4989    *
4990    * Writing this property sets the #ClutterActor:natural-width-set
4991    * property as well, as a side effect. This property overrides the
4992    * usual width request of the actor
4993    *
4994    * Since: 0.8
4995    */
4996   obj_props[PROP_NATURAL_WIDTH] =
4997     g_param_spec_float ("natural-width",
4998                         P_("Natural Width"),
4999                         P_("Forced natural width request for the actor"),
5000                         0.0, G_MAXFLOAT,
5001                         0.0,
5002                         CLUTTER_PARAM_READWRITE);
5003
5004   /**
5005    * ClutterActor:natural-height:
5006    *
5007    * A forced natural height request for the actor, in pixels
5008    *
5009    * Writing this property sets the #ClutterActor:natural-height-set
5010    * property as well, as a side effect. This property overrides the
5011    * usual height request of the actor
5012    *
5013    * Since: 0.8
5014    */
5015   obj_props[PROP_NATURAL_HEIGHT] =
5016     g_param_spec_float ("natural-height",
5017                         P_("Natural Height"),
5018                         P_("Forced natural height request for the actor"),
5019                         0.0, G_MAXFLOAT,
5020                         0.0,
5021                         CLUTTER_PARAM_READWRITE);
5022
5023   /**
5024    * ClutterActor:min-width-set:
5025    *
5026    * This flag controls whether the #ClutterActor:min-width property
5027    * is used
5028    *
5029    * Since: 0.8
5030    */
5031   obj_props[PROP_MIN_WIDTH_SET] =
5032     g_param_spec_boolean ("min-width-set",
5033                           P_("Minimum width set"),
5034                           P_("Whether to use the min-width property"),
5035                           FALSE,
5036                           CLUTTER_PARAM_READWRITE);
5037
5038   /**
5039    * ClutterActor:min-height-set:
5040    *
5041    * This flag controls whether the #ClutterActor:min-height property
5042    * is used
5043    *
5044    * Since: 0.8
5045    */
5046   obj_props[PROP_MIN_HEIGHT_SET] =
5047     g_param_spec_boolean ("min-height-set",
5048                           P_("Minimum height set"),
5049                           P_("Whether to use the min-height property"),
5050                           FALSE,
5051                           CLUTTER_PARAM_READWRITE);
5052
5053   /**
5054    * ClutterActor:natural-width-set:
5055    *
5056    * This flag controls whether the #ClutterActor:natural-width property
5057    * is used
5058    *
5059    * Since: 0.8
5060    */
5061   obj_props[PROP_NATURAL_WIDTH_SET] =
5062     g_param_spec_boolean ("natural-width-set",
5063                           P_("Natural width set"),
5064                           P_("Whether to use the natural-width property"),
5065                           FALSE,
5066                           CLUTTER_PARAM_READWRITE);
5067
5068   /**
5069    * ClutterActor:natural-height-set:
5070    *
5071    * This flag controls whether the #ClutterActor:natural-height property
5072    * is used
5073    *
5074    * Since: 0.8
5075    */
5076   obj_props[PROP_NATURAL_HEIGHT_SET] =
5077     g_param_spec_boolean ("natural-height-set",
5078                           P_("Natural height set"),
5079                           P_("Whether to use the natural-height property"),
5080                           FALSE,
5081                           CLUTTER_PARAM_READWRITE);
5082
5083   /**
5084    * ClutterActor:allocation:
5085    *
5086    * The allocation for the actor, in pixels
5087    *
5088    * This is property is read-only, but you might monitor it to know when an
5089    * actor moves or resizes
5090    *
5091    * Since: 0.8
5092    */
5093   obj_props[PROP_ALLOCATION] =
5094     g_param_spec_boxed ("allocation",
5095                         P_("Allocation"),
5096                         P_("The actor's allocation"),
5097                         CLUTTER_TYPE_ACTOR_BOX,
5098                         CLUTTER_PARAM_READABLE);
5099
5100   /**
5101    * ClutterActor:request-mode:
5102    *
5103    * Request mode for the #ClutterActor. The request mode determines the
5104    * type of geometry management used by the actor, either height for width
5105    * (the default) or width for height.
5106    *
5107    * For actors implementing height for width, the parent container should get
5108    * the preferred width first, and then the preferred height for that width.
5109    *
5110    * For actors implementing width for height, the parent container should get
5111    * the preferred height first, and then the preferred width for that height.
5112    *
5113    * For instance:
5114    *
5115    * |[
5116    *   ClutterRequestMode mode;
5117    *   gfloat natural_width, min_width;
5118    *   gfloat natural_height, min_height;
5119    *
5120    *   mode = clutter_actor_get_request_mode (child);
5121    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5122    *     {
5123    *       clutter_actor_get_preferred_width (child, -1,
5124    *                                          &amp;min_width,
5125    *                                          &amp;natural_width);
5126    *       clutter_actor_get_preferred_height (child, natural_width,
5127    *                                           &amp;min_height,
5128    *                                           &amp;natural_height);
5129    *     }
5130    *   else
5131    *     {
5132    *       clutter_actor_get_preferred_height (child, -1,
5133    *                                           &amp;min_height,
5134    *                                           &amp;natural_height);
5135    *       clutter_actor_get_preferred_width (child, natural_height,
5136    *                                          &amp;min_width,
5137    *                                          &amp;natural_width);
5138    *     }
5139    * ]|
5140    *
5141    * will retrieve the minimum and natural width and height depending on the
5142    * preferred request mode of the #ClutterActor "child".
5143    *
5144    * The clutter_actor_get_preferred_size() function will implement this
5145    * check for you.
5146    *
5147    * Since: 0.8
5148    */
5149   obj_props[PROP_REQUEST_MODE] =
5150     g_param_spec_enum ("request-mode",
5151                        P_("Request Mode"),
5152                        P_("The actor's request mode"),
5153                        CLUTTER_TYPE_REQUEST_MODE,
5154                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5155                        CLUTTER_PARAM_READWRITE);
5156
5157   /**
5158    * ClutterActor:depth:
5159    *
5160    * The position of the actor on the Z axis
5161    *
5162    * Since: 0.6
5163    */
5164   obj_props[PROP_DEPTH] =
5165     g_param_spec_float ("depth",
5166                         P_("Depth"),
5167                         P_("Position on the Z axis"),
5168                         -G_MAXFLOAT, G_MAXFLOAT,
5169                         0.0,
5170                         CLUTTER_PARAM_READWRITE);
5171
5172   /**
5173    * ClutterActor:opacity:
5174    *
5175    * Opacity of an actor, between 0 (fully transparent) and
5176    * 255 (fully opaque)
5177    */
5178   obj_props[PROP_OPACITY] =
5179     g_param_spec_uint ("opacity",
5180                        P_("Opacity"),
5181                        P_("Opacity of an actor"),
5182                        0, 255,
5183                        255,
5184                        CLUTTER_PARAM_READWRITE);
5185
5186   /**
5187    * ClutterActor:offscreen-redirect:
5188    *
5189    * Determines the conditions in which the actor will be redirected
5190    * to an offscreen framebuffer while being painted. For example this
5191    * can be used to cache an actor in a framebuffer or for improved
5192    * handling of transparent actors. See
5193    * clutter_actor_set_offscreen_redirect() for details.
5194    *
5195    * Since: 1.8
5196    */
5197   obj_props[PROP_OFFSCREEN_REDIRECT] =
5198     g_param_spec_flags ("offscreen-redirect",
5199                         P_("Offscreen redirect"),
5200                         P_("Flags controlling when to flatten the actor into a single image"),
5201                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5202                         0,
5203                         CLUTTER_PARAM_READWRITE);
5204
5205   /**
5206    * ClutterActor:visible:
5207    *
5208    * Whether the actor is set to be visible or not
5209    *
5210    * See also #ClutterActor:mapped
5211    */
5212   obj_props[PROP_VISIBLE] =
5213     g_param_spec_boolean ("visible",
5214                           P_("Visible"),
5215                           P_("Whether the actor is visible or not"),
5216                           FALSE,
5217                           CLUTTER_PARAM_READWRITE);
5218
5219   /**
5220    * ClutterActor:mapped:
5221    *
5222    * Whether the actor is mapped (will be painted when the stage
5223    * to which it belongs is mapped)
5224    *
5225    * Since: 1.0
5226    */
5227   obj_props[PROP_MAPPED] =
5228     g_param_spec_boolean ("mapped",
5229                           P_("Mapped"),
5230                           P_("Whether the actor will be painted"),
5231                           FALSE,
5232                           CLUTTER_PARAM_READABLE);
5233
5234   /**
5235    * ClutterActor:realized:
5236    *
5237    * Whether the actor has been realized
5238    *
5239    * Since: 1.0
5240    */
5241   obj_props[PROP_REALIZED] =
5242     g_param_spec_boolean ("realized",
5243                           P_("Realized"),
5244                           P_("Whether the actor has been realized"),
5245                           FALSE,
5246                           CLUTTER_PARAM_READABLE);
5247
5248   /**
5249    * ClutterActor:reactive:
5250    *
5251    * Whether the actor is reactive to events or not
5252    *
5253    * Only reactive actors will emit event-related signals
5254    *
5255    * Since: 0.6
5256    */
5257   obj_props[PROP_REACTIVE] =
5258     g_param_spec_boolean ("reactive",
5259                           P_("Reactive"),
5260                           P_("Whether the actor is reactive to events"),
5261                           FALSE,
5262                           CLUTTER_PARAM_READWRITE);
5263
5264   /**
5265    * ClutterActor:has-clip:
5266    *
5267    * Whether the actor has the #ClutterActor:clip property set or not
5268    */
5269   obj_props[PROP_HAS_CLIP] =
5270     g_param_spec_boolean ("has-clip",
5271                           P_("Has Clip"),
5272                           P_("Whether the actor has a clip set"),
5273                           FALSE,
5274                           CLUTTER_PARAM_READABLE);
5275
5276   /**
5277    * ClutterActor:clip:
5278    *
5279    * The clip region for the actor, in actor-relative coordinates
5280    *
5281    * Every part of the actor outside the clip region will not be
5282    * painted
5283    */
5284   obj_props[PROP_CLIP] =
5285     g_param_spec_boxed ("clip",
5286                         P_("Clip"),
5287                         P_("The clip region for the actor"),
5288                         CLUTTER_TYPE_GEOMETRY,
5289                         CLUTTER_PARAM_READWRITE);
5290
5291   /**
5292    * ClutterActor:name:
5293    *
5294    * The name of the actor
5295    *
5296    * Since: 0.2
5297    */
5298   obj_props[PROP_NAME] =
5299     g_param_spec_string ("name",
5300                          P_("Name"),
5301                          P_("Name of the actor"),
5302                          NULL,
5303                          CLUTTER_PARAM_READWRITE);
5304
5305   /**
5306    * ClutterActor:scale-x:
5307    *
5308    * The horizontal scale of the actor
5309    *
5310    * Since: 0.6
5311    */
5312   obj_props[PROP_SCALE_X] =
5313     g_param_spec_double ("scale-x",
5314                          P_("Scale X"),
5315                          P_("Scale factor on the X axis"),
5316                          0.0, G_MAXDOUBLE,
5317                          1.0,
5318                          CLUTTER_PARAM_READWRITE);
5319
5320   /**
5321    * ClutterActor:scale-y:
5322    *
5323    * The vertical scale of the actor
5324    *
5325    * Since: 0.6
5326    */
5327   obj_props[PROP_SCALE_Y] =
5328     g_param_spec_double ("scale-y",
5329                          P_("Scale Y"),
5330                          P_("Scale factor on the Y axis"),
5331                          0.0, G_MAXDOUBLE,
5332                          1.0,
5333                          CLUTTER_PARAM_READWRITE);
5334
5335   /**
5336    * ClutterActor:scale-center-x:
5337    *
5338    * The horizontal center point for scaling
5339    *
5340    * Since: 1.0
5341    */
5342   obj_props[PROP_SCALE_CENTER_X] =
5343     g_param_spec_float ("scale-center-x",
5344                         P_("Scale Center X"),
5345                         P_("Horizontal scale center"),
5346                         -G_MAXFLOAT, G_MAXFLOAT,
5347                         0.0,
5348                         CLUTTER_PARAM_READWRITE);
5349
5350   /**
5351    * ClutterActor:scale-center-y:
5352    *
5353    * The vertical center point for scaling
5354    *
5355    * Since: 1.0
5356    */
5357   obj_props[PROP_SCALE_CENTER_Y] =
5358     g_param_spec_float ("scale-center-y",
5359                         P_("Scale Center Y"),
5360                         P_("Vertical scale center"),
5361                         -G_MAXFLOAT, G_MAXFLOAT,
5362                         0.0,
5363                         CLUTTER_PARAM_READWRITE);
5364
5365   /**
5366    * ClutterActor:scale-gravity:
5367    *
5368    * The center point for scaling expressed as a #ClutterGravity
5369    *
5370    * Since: 1.0
5371    */
5372   obj_props[PROP_SCALE_GRAVITY] =
5373     g_param_spec_enum ("scale-gravity",
5374                        P_("Scale Gravity"),
5375                        P_("The center of scaling"),
5376                        CLUTTER_TYPE_GRAVITY,
5377                        CLUTTER_GRAVITY_NONE,
5378                        CLUTTER_PARAM_READWRITE);
5379
5380   /**
5381    * ClutterActor:rotation-angle-x:
5382    *
5383    * The rotation angle on the X axis
5384    *
5385    * Since: 0.6
5386    */
5387   obj_props[PROP_ROTATION_ANGLE_X] =
5388     g_param_spec_double ("rotation-angle-x",
5389                          P_("Rotation Angle X"),
5390                          P_("The rotation angle on the X axis"),
5391                          -G_MAXDOUBLE, G_MAXDOUBLE,
5392                          0.0,
5393                          CLUTTER_PARAM_READWRITE);
5394
5395   /**
5396    * ClutterActor:rotation-angle-y:
5397    *
5398    * The rotation angle on the Y axis
5399    *
5400    * Since: 0.6
5401    */
5402   obj_props[PROP_ROTATION_ANGLE_Y] =
5403     g_param_spec_double ("rotation-angle-y",
5404                          P_("Rotation Angle Y"),
5405                          P_("The rotation angle on the Y axis"),
5406                          -G_MAXDOUBLE, G_MAXDOUBLE,
5407                          0.0,
5408                          CLUTTER_PARAM_READWRITE);
5409
5410   /**
5411    * ClutterActor:rotation-angle-z:
5412    *
5413    * The rotation angle on the Z axis
5414    *
5415    * Since: 0.6
5416    */
5417   obj_props[PROP_ROTATION_ANGLE_Z] =
5418     g_param_spec_double ("rotation-angle-z",
5419                          P_("Rotation Angle Z"),
5420                          P_("The rotation angle on the Z axis"),
5421                          -G_MAXDOUBLE, G_MAXDOUBLE,
5422                          0.0,
5423                          CLUTTER_PARAM_READWRITE);
5424
5425   /**
5426    * ClutterActor:rotation-center-x:
5427    *
5428    * The rotation center on the X axis.
5429    *
5430    * Since: 0.6
5431    */
5432   obj_props[PROP_ROTATION_CENTER_X] =
5433     g_param_spec_boxed ("rotation-center-x",
5434                         P_("Rotation Center X"),
5435                         P_("The rotation center on the X axis"),
5436                         CLUTTER_TYPE_VERTEX,
5437                         CLUTTER_PARAM_READWRITE);
5438
5439   /**
5440    * ClutterActor:rotation-center-y:
5441    *
5442    * The rotation center on the Y axis.
5443    *
5444    * Since: 0.6
5445    */
5446   obj_props[PROP_ROTATION_CENTER_Y] =
5447     g_param_spec_boxed ("rotation-center-y",
5448                         P_("Rotation Center Y"),
5449                         P_("The rotation center on the Y axis"),
5450                         CLUTTER_TYPE_VERTEX,
5451                         CLUTTER_PARAM_READWRITE);
5452
5453   /**
5454    * ClutterActor:rotation-center-z:
5455    *
5456    * The rotation center on the Z axis.
5457    *
5458    * Since: 0.6
5459    */
5460   obj_props[PROP_ROTATION_CENTER_Z] =
5461     g_param_spec_boxed ("rotation-center-z",
5462                         P_("Rotation Center Z"),
5463                         P_("The rotation center on the Z axis"),
5464                         CLUTTER_TYPE_VERTEX,
5465                         CLUTTER_PARAM_READWRITE);
5466
5467   /**
5468    * ClutterActor:rotation-center-z-gravity:
5469    *
5470    * The rotation center on the Z axis expressed as a #ClutterGravity.
5471    *
5472    * Since: 1.0
5473    */
5474   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5475     g_param_spec_enum ("rotation-center-z-gravity",
5476                        P_("Rotation Center Z Gravity"),
5477                        P_("Center point for rotation around the Z axis"),
5478                        CLUTTER_TYPE_GRAVITY,
5479                        CLUTTER_GRAVITY_NONE,
5480                        CLUTTER_PARAM_READWRITE);
5481
5482   /**
5483    * ClutterActor:anchor-x:
5484    *
5485    * The X coordinate of an actor's anchor point, relative to
5486    * the actor coordinate space, in pixels
5487    *
5488    * Since: 0.8
5489    */
5490   obj_props[PROP_ANCHOR_X] =
5491     g_param_spec_float ("anchor-x",
5492                         P_("Anchor X"),
5493                         P_("X coordinate of the anchor point"),
5494                         -G_MAXFLOAT, G_MAXFLOAT,
5495                         0,
5496                         CLUTTER_PARAM_READWRITE);
5497
5498   /**
5499    * ClutterActor:anchor-y:
5500    *
5501    * The Y coordinate of an actor's anchor point, relative to
5502    * the actor coordinate space, in pixels
5503    *
5504    * Since: 0.8
5505    */
5506   obj_props[PROP_ANCHOR_Y] =
5507     g_param_spec_float ("anchor-y",
5508                         P_("Anchor Y"),
5509                         P_("Y coordinate of the anchor point"),
5510                         -G_MAXFLOAT, G_MAXFLOAT,
5511                         0,
5512                         CLUTTER_PARAM_READWRITE);
5513
5514   /**
5515    * ClutterActor:anchor-gravity:
5516    *
5517    * The anchor point expressed as a #ClutterGravity
5518    *
5519    * Since: 1.0
5520    */
5521   obj_props[PROP_ANCHOR_GRAVITY] =
5522     g_param_spec_enum ("anchor-gravity",
5523                        P_("Anchor Gravity"),
5524                        P_("The anchor point as a ClutterGravity"),
5525                        CLUTTER_TYPE_GRAVITY,
5526                        CLUTTER_GRAVITY_NONE,
5527                        CLUTTER_PARAM_READWRITE);
5528
5529   /**
5530    * ClutterActor:show-on-set-parent:
5531    *
5532    * If %TRUE, the actor is automatically shown when parented.
5533    *
5534    * Calling clutter_actor_hide() on an actor which has not been
5535    * parented will set this property to %FALSE as a side effect.
5536    *
5537    * Since: 0.8
5538    */
5539   obj_props[PROP_SHOW_ON_SET_PARENT] =
5540     g_param_spec_boolean ("show-on-set-parent",
5541                           P_("Show on set parent"),
5542                           P_("Whether the actor is shown when parented"),
5543                           TRUE,
5544                           CLUTTER_PARAM_READWRITE);
5545
5546   /**
5547    * ClutterActor:clip-to-allocation:
5548    *
5549    * Whether the clip region should track the allocated area
5550    * of the actor.
5551    *
5552    * This property is ignored if a clip area has been explicitly
5553    * set using clutter_actor_set_clip().
5554    *
5555    * Since: 1.0
5556    */
5557   obj_props[PROP_CLIP_TO_ALLOCATION] =
5558     g_param_spec_boolean ("clip-to-allocation",
5559                           P_("Clip to Allocation"),
5560                           P_("Sets the clip region to track the actor's allocation"),
5561                           FALSE,
5562                           CLUTTER_PARAM_READWRITE);
5563
5564   /**
5565    * ClutterActor:text-direction:
5566    *
5567    * The direction of the text inside a #ClutterActor.
5568    *
5569    * Since: 1.0
5570    */
5571   obj_props[PROP_TEXT_DIRECTION] =
5572     g_param_spec_enum ("text-direction",
5573                        P_("Text Direction"),
5574                        P_("Direction of the text"),
5575                        CLUTTER_TYPE_TEXT_DIRECTION,
5576                        CLUTTER_TEXT_DIRECTION_LTR,
5577                        CLUTTER_PARAM_READWRITE);
5578
5579   /**
5580    * ClutterActor:has-pointer:
5581    *
5582    * Whether the actor contains the pointer of a #ClutterInputDevice
5583    * or not.
5584    *
5585    * Since: 1.2
5586    */
5587   obj_props[PROP_HAS_POINTER] =
5588     g_param_spec_boolean ("has-pointer",
5589                           P_("Has Pointer"),
5590                           P_("Whether the actor contains the pointer of an input device"),
5591                           FALSE,
5592                           CLUTTER_PARAM_READABLE);
5593
5594   /**
5595    * ClutterActor:actions:
5596    *
5597    * Adds a #ClutterAction to the actor
5598    *
5599    * Since: 1.4
5600    */
5601   obj_props[PROP_ACTIONS] =
5602     g_param_spec_object ("actions",
5603                          P_("Actions"),
5604                          P_("Adds an action to the actor"),
5605                          CLUTTER_TYPE_ACTION,
5606                          CLUTTER_PARAM_WRITABLE);
5607
5608   /**
5609    * ClutterActor:constraints:
5610    *
5611    * Adds a #ClutterConstraint to the actor
5612    *
5613    * Since: 1.4
5614    */
5615   obj_props[PROP_CONSTRAINTS] =
5616     g_param_spec_object ("constraints",
5617                          P_("Constraints"),
5618                          P_("Adds a constraint to the actor"),
5619                          CLUTTER_TYPE_CONSTRAINT,
5620                          CLUTTER_PARAM_WRITABLE);
5621
5622   /**
5623    * ClutterActor:effect:
5624    *
5625    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5626    *
5627    * Since: 1.4
5628    */
5629   obj_props[PROP_EFFECT] =
5630     g_param_spec_object ("effect",
5631                          P_("Effect"),
5632                          P_("Add an effect to be applied on the actor"),
5633                          CLUTTER_TYPE_EFFECT,
5634                          CLUTTER_PARAM_WRITABLE);
5635
5636   /**
5637    * ClutterActor:layout-manager:
5638    *
5639    * A delegate object for controlling the layout of the children of
5640    * an actor.
5641    *
5642    * Since: 1.10
5643    */
5644   obj_props[PROP_LAYOUT_MANAGER] =
5645     g_param_spec_object ("layout-manager",
5646                          P_("Layout Manager"),
5647                          P_("The object controlling the layout of an actor's children"),
5648                          CLUTTER_TYPE_LAYOUT_MANAGER,
5649                          CLUTTER_PARAM_READWRITE);
5650
5651
5652   /**
5653    * ClutterActor:x-align:
5654    *
5655    * The alignment of an actor on the X axis, if the actor has been given
5656    * extra space for its allocation.
5657    *
5658    * Since: 1.10
5659    */
5660   obj_props[PROP_X_ALIGN] =
5661     g_param_spec_enum ("x-align",
5662                        P_("X Alignment"),
5663                        P_("The alignment of the actor on the X axis within its allocation"),
5664                        CLUTTER_TYPE_ACTOR_ALIGN,
5665                        CLUTTER_ACTOR_ALIGN_FILL,
5666                        CLUTTER_PARAM_READWRITE);
5667
5668   /**
5669    * ClutterActor:y-align:
5670    *
5671    * The alignment of an actor on the Y axis, if the actor has been given
5672    * extra space for its allocation.
5673    *
5674    * Since: 1.10
5675    */
5676   obj_props[PROP_Y_ALIGN] =
5677     g_param_spec_enum ("y-align",
5678                        P_("Y Alignment"),
5679                        P_("The alignment of the actor on the Y axis within its allocation"),
5680                        CLUTTER_TYPE_ACTOR_ALIGN,
5681                        CLUTTER_ACTOR_ALIGN_FILL,
5682                        CLUTTER_PARAM_READWRITE);
5683
5684   /**
5685    * ClutterActor:margin-top:
5686    *
5687    * The margin (in pixels) from the top of the actor.
5688    *
5689    * This property adds a margin to the actor's preferred size; the margin
5690    * will be automatically taken into account when allocating the actor.
5691    *
5692    * Since: 1.10
5693    */
5694   obj_props[PROP_MARGIN_TOP] =
5695     g_param_spec_float ("margin-top",
5696                         P_("Margin Top"),
5697                         P_("Extra space at the top"),
5698                         0.0, G_MAXFLOAT,
5699                         0.0,
5700                         CLUTTER_PARAM_READWRITE);
5701
5702   /**
5703    * ClutterActor:margin-bottom:
5704    *
5705    * The margin (in pixels) from the bottom of the actor.
5706    *
5707    * This property adds a margin to the actor's preferred size; the margin
5708    * will be automatically taken into account when allocating the actor.
5709    *
5710    * Since: 1.10
5711    */
5712   obj_props[PROP_MARGIN_BOTTOM] =
5713     g_param_spec_float ("margin-bottom",
5714                         P_("Margin Bottom"),
5715                         P_("Extra space at the bottom"),
5716                         0.0, G_MAXFLOAT,
5717                         0.0,
5718                         CLUTTER_PARAM_READWRITE);
5719
5720   /**
5721    * ClutterActor:margin-left:
5722    *
5723    * The margin (in pixels) from the left of the actor.
5724    *
5725    * This property adds a margin to the actor's preferred size; the margin
5726    * will be automatically taken into account when allocating the actor.
5727    *
5728    * Since: 1.10
5729    */
5730   obj_props[PROP_MARGIN_LEFT] =
5731     g_param_spec_float ("margin-left",
5732                         P_("Margin Left"),
5733                         P_("Extra space at the left"),
5734                         0.0, G_MAXFLOAT,
5735                         0.0,
5736                         CLUTTER_PARAM_READWRITE);
5737
5738   /**
5739    * ClutterActor:margin-right:
5740    *
5741    * The margin (in pixels) from the right of the actor.
5742    *
5743    * This property adds a margin to the actor's preferred size; the margin
5744    * will be automatically taken into account when allocating the actor.
5745    *
5746    * Since: 1.10
5747    */
5748   obj_props[PROP_MARGIN_RIGHT] =
5749     g_param_spec_float ("margin-right",
5750                         P_("Margin Right"),
5751                         P_("Extra space at the right"),
5752                         0.0, G_MAXFLOAT,
5753                         0.0,
5754                         CLUTTER_PARAM_READWRITE);
5755
5756   /**
5757    * ClutterActor:background-color-set:
5758    *
5759    * Whether the #ClutterActor:background-color property has been set.
5760    *
5761    * Since: 1.10
5762    */
5763   obj_props[PROP_BACKGROUND_COLOR_SET] =
5764     g_param_spec_boolean ("background-color-set",
5765                           P_("Background Color Set"),
5766                           P_("Whether the background color is set"),
5767                           FALSE,
5768                           CLUTTER_PARAM_READABLE);
5769
5770   /**
5771    * ClutterActor:background-color:
5772    *
5773    * Paints a solid fill of the actor's allocation using the specified
5774    * color.
5775    *
5776    * Since: 1.10
5777    */
5778   obj_props[PROP_BACKGROUND_COLOR] =
5779     clutter_param_spec_color ("background-color",
5780                               P_("Background color"),
5781                               P_("The actor's background color"),
5782                               CLUTTER_COLOR_Transparent,
5783                               CLUTTER_PARAM_READWRITE);
5784
5785   /**
5786    * ClutterActor:first-child:
5787    *
5788    * The actor's first child.
5789    *
5790    * Since: 1.10
5791    */
5792   obj_props[PROP_FIRST_CHILD] =
5793     g_param_spec_object ("first-child",
5794                          P_("First Child"),
5795                          P_("The actor's first child"),
5796                          CLUTTER_TYPE_ACTOR,
5797                          CLUTTER_PARAM_READABLE);
5798
5799   /**
5800    * ClutterActor:last-child:
5801    *
5802    * The actor's last child.
5803    *
5804    * Since: 1.10
5805    */
5806   obj_props[PROP_LAST_CHILD] =
5807     g_param_spec_object ("last-child",
5808                          P_("Last Child"),
5809                          P_("The actor's last child"),
5810                          CLUTTER_TYPE_ACTOR,
5811                          CLUTTER_PARAM_READABLE);
5812
5813   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5814
5815   /**
5816    * ClutterActor::destroy:
5817    * @actor: the #ClutterActor which emitted the signal
5818    *
5819    * The ::destroy signal notifies that all references held on the
5820    * actor which emitted it should be released.
5821    *
5822    * The ::destroy signal should be used by all holders of a reference
5823    * on @actor.
5824    *
5825    * This signal might result in the finalization of the #ClutterActor
5826    * if all references are released.
5827    *
5828    * Composite actors and actors implementing the #ClutterContainer
5829    * interface should override the default implementation of the
5830    * class handler of this signal and call clutter_actor_destroy() on
5831    * their children. When overriding the default class handler, it is
5832    * required to chain up to the parent's implementation.
5833    *
5834    * Since: 0.2
5835    */
5836   actor_signals[DESTROY] =
5837     g_signal_new (I_("destroy"),
5838                   G_TYPE_FROM_CLASS (object_class),
5839                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5840                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5841                   NULL, NULL,
5842                   _clutter_marshal_VOID__VOID,
5843                   G_TYPE_NONE, 0);
5844   /**
5845    * ClutterActor::show:
5846    * @actor: the object which received the signal
5847    *
5848    * The ::show signal is emitted when an actor is visible and
5849    * rendered on the stage.
5850    *
5851    * Since: 0.2
5852    */
5853   actor_signals[SHOW] =
5854     g_signal_new (I_("show"),
5855                   G_TYPE_FROM_CLASS (object_class),
5856                   G_SIGNAL_RUN_FIRST,
5857                   G_STRUCT_OFFSET (ClutterActorClass, show),
5858                   NULL, NULL,
5859                   _clutter_marshal_VOID__VOID,
5860                   G_TYPE_NONE, 0);
5861   /**
5862    * ClutterActor::hide:
5863    * @actor: the object which received the signal
5864    *
5865    * The ::hide signal is emitted when an actor is no longer rendered
5866    * on the stage.
5867    *
5868    * Since: 0.2
5869    */
5870   actor_signals[HIDE] =
5871     g_signal_new (I_("hide"),
5872                   G_TYPE_FROM_CLASS (object_class),
5873                   G_SIGNAL_RUN_FIRST,
5874                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5875                   NULL, NULL,
5876                   _clutter_marshal_VOID__VOID,
5877                   G_TYPE_NONE, 0);
5878   /**
5879    * ClutterActor::parent-set:
5880    * @actor: the object which received the signal
5881    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5882    *
5883    * This signal is emitted when the parent of the actor changes.
5884    *
5885    * Since: 0.2
5886    */
5887   actor_signals[PARENT_SET] =
5888     g_signal_new (I_("parent-set"),
5889                   G_TYPE_FROM_CLASS (object_class),
5890                   G_SIGNAL_RUN_LAST,
5891                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5892                   NULL, NULL,
5893                   _clutter_marshal_VOID__OBJECT,
5894                   G_TYPE_NONE, 1,
5895                   CLUTTER_TYPE_ACTOR);
5896
5897   /**
5898    * ClutterActor::queue-redraw:
5899    * @actor: the actor we're bubbling the redraw request through
5900    * @origin: the actor which initiated the redraw request
5901    *
5902    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5903    * is called on @origin.
5904    *
5905    * The default implementation for #ClutterActor chains up to the
5906    * parent actor and queues a redraw on the parent, thus "bubbling"
5907    * the redraw queue up through the actor graph. The default
5908    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5909    * in a main loop idle handler.
5910    *
5911    * Note that the @origin actor may be the stage, or a container; it
5912    * does not have to be a leaf node in the actor graph.
5913    *
5914    * Toolkits embedding a #ClutterStage which require a redraw and
5915    * relayout cycle can stop the emission of this signal using the
5916    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5917    * themselves, like:
5918    *
5919    * |[
5920    *   static void
5921    *   on_redraw_complete (gpointer data)
5922    *   {
5923    *     ClutterStage *stage = data;
5924    *
5925    *     /&ast; execute the Clutter drawing pipeline &ast;/
5926    *     clutter_stage_ensure_redraw (stage);
5927    *   }
5928    *
5929    *   static void
5930    *   on_stage_queue_redraw (ClutterStage *stage)
5931    *   {
5932    *     /&ast; this prevents the default handler to run &ast;/
5933    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5934    *
5935    *     /&ast; queue a redraw with the host toolkit and call
5936    *      &ast; a function when the redraw has been completed
5937    *      &ast;/
5938    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5939    *   }
5940    * ]|
5941    *
5942    * <note><para>This signal is emitted before the Clutter paint
5943    * pipeline is executed. If you want to know when the pipeline has
5944    * been completed you should connect to the ::paint signal on the
5945    * Stage with g_signal_connect_after().</para></note>
5946    *
5947    * Since: 1.0
5948    */
5949   actor_signals[QUEUE_REDRAW] =
5950     g_signal_new (I_("queue-redraw"),
5951                   G_TYPE_FROM_CLASS (object_class),
5952                   G_SIGNAL_RUN_LAST,
5953                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5954                   NULL, NULL,
5955                   _clutter_marshal_VOID__OBJECT,
5956                   G_TYPE_NONE, 1,
5957                   CLUTTER_TYPE_ACTOR);
5958
5959   /**
5960    * ClutterActor::queue-relayout
5961    * @actor: the actor being queued for relayout
5962    *
5963    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5964    * is called on an actor.
5965    *
5966    * The default implementation for #ClutterActor chains up to the
5967    * parent actor and queues a relayout on the parent, thus "bubbling"
5968    * the relayout queue up through the actor graph.
5969    *
5970    * The main purpose of this signal is to allow relayout to be propagated
5971    * properly in the procense of #ClutterClone actors. Applications will
5972    * not normally need to connect to this signal.
5973    *
5974    * Since: 1.2
5975    */
5976   actor_signals[QUEUE_RELAYOUT] =
5977     g_signal_new (I_("queue-relayout"),
5978                   G_TYPE_FROM_CLASS (object_class),
5979                   G_SIGNAL_RUN_LAST,
5980                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
5981                   NULL, NULL,
5982                   _clutter_marshal_VOID__VOID,
5983                   G_TYPE_NONE, 0);
5984
5985   /**
5986    * ClutterActor::event:
5987    * @actor: the actor which received the event
5988    * @event: a #ClutterEvent
5989    *
5990    * The ::event signal is emitted each time an event is received
5991    * by the @actor. This signal will be emitted on every actor,
5992    * following the hierarchy chain, until it reaches the top-level
5993    * container (the #ClutterStage).
5994    *
5995    * Return value: %TRUE if the event has been handled by the actor,
5996    *   or %FALSE to continue the emission.
5997    *
5998    * Since: 0.6
5999    */
6000   actor_signals[EVENT] =
6001     g_signal_new (I_("event"),
6002                   G_TYPE_FROM_CLASS (object_class),
6003                   G_SIGNAL_RUN_LAST,
6004                   G_STRUCT_OFFSET (ClutterActorClass, event),
6005                   _clutter_boolean_handled_accumulator, NULL,
6006                   _clutter_marshal_BOOLEAN__BOXED,
6007                   G_TYPE_BOOLEAN, 1,
6008                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6009   /**
6010    * ClutterActor::button-press-event:
6011    * @actor: the actor which received the event
6012    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6013    *
6014    * The ::button-press-event signal is emitted each time a mouse button
6015    * is pressed on @actor.
6016    *
6017    * Return value: %TRUE if the event has been handled by the actor,
6018    *   or %FALSE to continue the emission.
6019    *
6020    * Since: 0.6
6021    */
6022   actor_signals[BUTTON_PRESS_EVENT] =
6023     g_signal_new (I_("button-press-event"),
6024                   G_TYPE_FROM_CLASS (object_class),
6025                   G_SIGNAL_RUN_LAST,
6026                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6027                   _clutter_boolean_handled_accumulator, NULL,
6028                   _clutter_marshal_BOOLEAN__BOXED,
6029                   G_TYPE_BOOLEAN, 1,
6030                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6031   /**
6032    * ClutterActor::button-release-event:
6033    * @actor: the actor which received the event
6034    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6035    *
6036    * The ::button-release-event signal is emitted each time a mouse button
6037    * is released on @actor.
6038    *
6039    * Return value: %TRUE if the event has been handled by the actor,
6040    *   or %FALSE to continue the emission.
6041    *
6042    * Since: 0.6
6043    */
6044   actor_signals[BUTTON_RELEASE_EVENT] =
6045     g_signal_new (I_("button-release-event"),
6046                   G_TYPE_FROM_CLASS (object_class),
6047                   G_SIGNAL_RUN_LAST,
6048                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6049                   _clutter_boolean_handled_accumulator, NULL,
6050                   _clutter_marshal_BOOLEAN__BOXED,
6051                   G_TYPE_BOOLEAN, 1,
6052                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6053   /**
6054    * ClutterActor::scroll-event:
6055    * @actor: the actor which received the event
6056    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6057    *
6058    * The ::scroll-event signal is emitted each time the mouse is
6059    * scrolled on @actor
6060    *
6061    * Return value: %TRUE if the event has been handled by the actor,
6062    *   or %FALSE to continue the emission.
6063    *
6064    * Since: 0.6
6065    */
6066   actor_signals[SCROLL_EVENT] =
6067     g_signal_new (I_("scroll-event"),
6068                   G_TYPE_FROM_CLASS (object_class),
6069                   G_SIGNAL_RUN_LAST,
6070                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6071                   _clutter_boolean_handled_accumulator, NULL,
6072                   _clutter_marshal_BOOLEAN__BOXED,
6073                   G_TYPE_BOOLEAN, 1,
6074                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6075   /**
6076    * ClutterActor::key-press-event:
6077    * @actor: the actor which received the event
6078    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6079    *
6080    * The ::key-press-event signal is emitted each time a keyboard button
6081    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6082    *
6083    * Return value: %TRUE if the event has been handled by the actor,
6084    *   or %FALSE to continue the emission.
6085    *
6086    * Since: 0.6
6087    */
6088   actor_signals[KEY_PRESS_EVENT] =
6089     g_signal_new (I_("key-press-event"),
6090                   G_TYPE_FROM_CLASS (object_class),
6091                   G_SIGNAL_RUN_LAST,
6092                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6093                   _clutter_boolean_handled_accumulator, NULL,
6094                   _clutter_marshal_BOOLEAN__BOXED,
6095                   G_TYPE_BOOLEAN, 1,
6096                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6097   /**
6098    * ClutterActor::key-release-event:
6099    * @actor: the actor which received the event
6100    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6101    *
6102    * The ::key-release-event signal is emitted each time a keyboard button
6103    * is released while @actor has key focus (see
6104    * clutter_stage_set_key_focus()).
6105    *
6106    * Return value: %TRUE if the event has been handled by the actor,
6107    *   or %FALSE to continue the emission.
6108    *
6109    * Since: 0.6
6110    */
6111   actor_signals[KEY_RELEASE_EVENT] =
6112     g_signal_new (I_("key-release-event"),
6113                   G_TYPE_FROM_CLASS (object_class),
6114                   G_SIGNAL_RUN_LAST,
6115                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6116                   _clutter_boolean_handled_accumulator, NULL,
6117                   _clutter_marshal_BOOLEAN__BOXED,
6118                   G_TYPE_BOOLEAN, 1,
6119                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6120   /**
6121    * ClutterActor::motion-event:
6122    * @actor: the actor which received the event
6123    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6124    *
6125    * The ::motion-event signal is emitted each time the mouse pointer is
6126    * moved over @actor.
6127    *
6128    * Return value: %TRUE if the event has been handled by the actor,
6129    *   or %FALSE to continue the emission.
6130    *
6131    * Since: 0.6
6132    */
6133   actor_signals[MOTION_EVENT] =
6134     g_signal_new (I_("motion-event"),
6135                   G_TYPE_FROM_CLASS (object_class),
6136                   G_SIGNAL_RUN_LAST,
6137                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6138                   _clutter_boolean_handled_accumulator, NULL,
6139                   _clutter_marshal_BOOLEAN__BOXED,
6140                   G_TYPE_BOOLEAN, 1,
6141                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6142
6143   /**
6144    * ClutterActor::key-focus-in:
6145    * @actor: the actor which now has key focus
6146    *
6147    * The ::key-focus-in signal is emitted when @actor receives key focus.
6148    *
6149    * Since: 0.6
6150    */
6151   actor_signals[KEY_FOCUS_IN] =
6152     g_signal_new (I_("key-focus-in"),
6153                   G_TYPE_FROM_CLASS (object_class),
6154                   G_SIGNAL_RUN_LAST,
6155                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6156                   NULL, NULL,
6157                   _clutter_marshal_VOID__VOID,
6158                   G_TYPE_NONE, 0);
6159
6160   /**
6161    * ClutterActor::key-focus-out:
6162    * @actor: the actor which now has key focus
6163    *
6164    * The ::key-focus-out signal is emitted when @actor loses key focus.
6165    *
6166    * Since: 0.6
6167    */
6168   actor_signals[KEY_FOCUS_OUT] =
6169     g_signal_new (I_("key-focus-out"),
6170                   G_TYPE_FROM_CLASS (object_class),
6171                   G_SIGNAL_RUN_LAST,
6172                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6173                   NULL, NULL,
6174                   _clutter_marshal_VOID__VOID,
6175                   G_TYPE_NONE, 0);
6176
6177   /**
6178    * ClutterActor::enter-event:
6179    * @actor: the actor which the pointer has entered.
6180    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6181    *
6182    * The ::enter-event signal is emitted when the pointer enters the @actor
6183    *
6184    * Return value: %TRUE if the event has been handled by the actor,
6185    *   or %FALSE to continue the emission.
6186    *
6187    * Since: 0.6
6188    */
6189   actor_signals[ENTER_EVENT] =
6190     g_signal_new (I_("enter-event"),
6191                   G_TYPE_FROM_CLASS (object_class),
6192                   G_SIGNAL_RUN_LAST,
6193                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6194                   _clutter_boolean_handled_accumulator, NULL,
6195                   _clutter_marshal_BOOLEAN__BOXED,
6196                   G_TYPE_BOOLEAN, 1,
6197                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6198
6199   /**
6200    * ClutterActor::leave-event:
6201    * @actor: the actor which the pointer has left
6202    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6203    *
6204    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6205    *
6206    * Return value: %TRUE if the event has been handled by the actor,
6207    *   or %FALSE to continue the emission.
6208    *
6209    * Since: 0.6
6210    */
6211   actor_signals[LEAVE_EVENT] =
6212     g_signal_new (I_("leave-event"),
6213                   G_TYPE_FROM_CLASS (object_class),
6214                   G_SIGNAL_RUN_LAST,
6215                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6216                   _clutter_boolean_handled_accumulator, NULL,
6217                   _clutter_marshal_BOOLEAN__BOXED,
6218                   G_TYPE_BOOLEAN, 1,
6219                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6220
6221   /**
6222    * ClutterActor::captured-event:
6223    * @actor: the actor which received the signal
6224    * @event: a #ClutterEvent
6225    *
6226    * The ::captured-event signal is emitted when an event is captured
6227    * by Clutter. This signal will be emitted starting from the top-level
6228    * container (the #ClutterStage) to the actor which received the event
6229    * going down the hierarchy. This signal can be used to intercept every
6230    * event before the specialized events (like
6231    * ClutterActor::button-press-event or ::key-released-event) are
6232    * emitted.
6233    *
6234    * Return value: %TRUE if the event has been handled by the actor,
6235    *   or %FALSE to continue the emission.
6236    *
6237    * Since: 0.6
6238    */
6239   actor_signals[CAPTURED_EVENT] =
6240     g_signal_new (I_("captured-event"),
6241                   G_TYPE_FROM_CLASS (object_class),
6242                   G_SIGNAL_RUN_LAST,
6243                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6244                   _clutter_boolean_handled_accumulator, NULL,
6245                   _clutter_marshal_BOOLEAN__BOXED,
6246                   G_TYPE_BOOLEAN, 1,
6247                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6248
6249   /**
6250    * ClutterActor::paint:
6251    * @actor: the #ClutterActor that received the signal
6252    *
6253    * The ::paint signal is emitted each time an actor is being painted.
6254    *
6255    * Subclasses of #ClutterActor should override the class signal handler
6256    * and paint themselves in that function.
6257    *
6258    * It is possible to connect a handler to the ::paint signal in order
6259    * to set up some custom aspect of a paint.
6260    *
6261    * Since: 0.8
6262    */
6263   actor_signals[PAINT] =
6264     g_signal_new (I_("paint"),
6265                   G_TYPE_FROM_CLASS (object_class),
6266                   G_SIGNAL_RUN_LAST,
6267                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6268                   NULL, NULL,
6269                   _clutter_marshal_VOID__VOID,
6270                   G_TYPE_NONE, 0);
6271   /**
6272    * ClutterActor::realize:
6273    * @actor: the #ClutterActor that received the signal
6274    *
6275    * The ::realize signal is emitted each time an actor is being
6276    * realized.
6277    *
6278    * Since: 0.8
6279    */
6280   actor_signals[REALIZE] =
6281     g_signal_new (I_("realize"),
6282                   G_TYPE_FROM_CLASS (object_class),
6283                   G_SIGNAL_RUN_LAST,
6284                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6285                   NULL, NULL,
6286                   _clutter_marshal_VOID__VOID,
6287                   G_TYPE_NONE, 0);
6288   /**
6289    * ClutterActor::unrealize:
6290    * @actor: the #ClutterActor that received the signal
6291    *
6292    * The ::unrealize signal is emitted each time an actor is being
6293    * unrealized.
6294    *
6295    * Since: 0.8
6296    */
6297   actor_signals[UNREALIZE] =
6298     g_signal_new (I_("unrealize"),
6299                   G_TYPE_FROM_CLASS (object_class),
6300                   G_SIGNAL_RUN_LAST,
6301                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6302                   NULL, NULL,
6303                   _clutter_marshal_VOID__VOID,
6304                   G_TYPE_NONE, 0);
6305
6306   /**
6307    * ClutterActor::pick:
6308    * @actor: the #ClutterActor that received the signal
6309    * @color: the #ClutterColor to be used when picking
6310    *
6311    * The ::pick signal is emitted each time an actor is being painted
6312    * in "pick mode". The pick mode is used to identify the actor during
6313    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6314    * The actor should paint its shape using the passed @pick_color.
6315    *
6316    * Subclasses of #ClutterActor should override the class signal handler
6317    * and paint themselves in that function.
6318    *
6319    * It is possible to connect a handler to the ::pick signal in order
6320    * to set up some custom aspect of a paint in pick mode.
6321    *
6322    * Since: 1.0
6323    */
6324   actor_signals[PICK] =
6325     g_signal_new (I_("pick"),
6326                   G_TYPE_FROM_CLASS (object_class),
6327                   G_SIGNAL_RUN_LAST,
6328                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6329                   NULL, NULL,
6330                   _clutter_marshal_VOID__BOXED,
6331                   G_TYPE_NONE, 1,
6332                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6333
6334   /**
6335    * ClutterActor::allocation-changed:
6336    * @actor: the #ClutterActor that emitted the signal
6337    * @box: a #ClutterActorBox with the new allocation
6338    * @flags: #ClutterAllocationFlags for the allocation
6339    *
6340    * The ::allocation-changed signal is emitted when the
6341    * #ClutterActor:allocation property changes. Usually, application
6342    * code should just use the notifications for the :allocation property
6343    * but if you want to track the allocation flags as well, for instance
6344    * to know whether the absolute origin of @actor changed, then you might
6345    * want use this signal instead.
6346    *
6347    * Since: 1.0
6348    */
6349   actor_signals[ALLOCATION_CHANGED] =
6350     g_signal_new (I_("allocation-changed"),
6351                   G_TYPE_FROM_CLASS (object_class),
6352                   G_SIGNAL_RUN_LAST,
6353                   0,
6354                   NULL, NULL,
6355                   _clutter_marshal_VOID__BOXED_FLAGS,
6356                   G_TYPE_NONE, 2,
6357                   CLUTTER_TYPE_ACTOR_BOX,
6358                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6359 }
6360
6361 static void
6362 clutter_actor_init (ClutterActor *self)
6363 {
6364   ClutterActorPrivate *priv;
6365
6366   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6367
6368   priv->id = _clutter_context_acquire_id (self);
6369   priv->pick_id = -1;
6370
6371   priv->opacity = 0xff;
6372   priv->show_on_set_parent = TRUE;
6373
6374   priv->needs_width_request = TRUE;
6375   priv->needs_height_request = TRUE;
6376   priv->needs_allocation = TRUE;
6377
6378   priv->cached_width_age = 1;
6379   priv->cached_height_age = 1;
6380
6381   priv->opacity_override = -1;
6382   priv->enable_model_view_transform = TRUE;
6383
6384   /* Initialize an empty paint volume to start with */
6385   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6386   priv->last_paint_volume_valid = TRUE;
6387
6388   priv->transform_valid = FALSE;
6389 }
6390
6391 /**
6392  * clutter_actor_new:
6393  *
6394  * Creates a new #ClutterActor.
6395  *
6396  * A newly created actor has a floating reference, which will be sunk
6397  * when it is added to another actor.
6398  *
6399  * Return value: (transfer full): the newly created #ClutterActor
6400  *
6401  * Since: 1.10
6402  */
6403 ClutterActor *
6404 clutter_actor_new (void)
6405 {
6406   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6407 }
6408
6409 /**
6410  * clutter_actor_destroy:
6411  * @self: a #ClutterActor
6412  *
6413  * Destroys an actor.  When an actor is destroyed, it will break any
6414  * references it holds to other objects.  If the actor is inside a
6415  * container, the actor will be removed.
6416  *
6417  * When you destroy a container, its children will be destroyed as well.
6418  *
6419  * Note: you cannot destroy the #ClutterStage returned by
6420  * clutter_stage_get_default().
6421  */
6422 void
6423 clutter_actor_destroy (ClutterActor *self)
6424 {
6425   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6426
6427   g_object_ref (self);
6428
6429   /* avoid recursion while destroying */
6430   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6431     {
6432       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6433
6434       g_object_run_dispose (G_OBJECT (self));
6435
6436       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6437     }
6438
6439   g_object_unref (self);
6440 }
6441
6442 void
6443 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6444                                     ClutterPaintVolume *clip)
6445 {
6446   ClutterActorPrivate *priv = self->priv;
6447   ClutterPaintVolume *pv;
6448   gboolean clipped;
6449
6450   /* If we've been explicitly passed a clip volume then there's
6451    * nothing more to calculate, but otherwise the only thing we know
6452    * is that the change is constrained to the given actor.
6453    *
6454    * The idea is that if we know the paint volume for where the actor
6455    * was last drawn (in eye coordinates) and we also have the paint
6456    * volume for where it will be drawn next (in actor coordinates)
6457    * then if we queue a redraw for both these volumes that will cover
6458    * everything that needs to be redrawn to clear the old view and
6459    * show the latest view of the actor.
6460    *
6461    * Don't clip this redraw if we don't know what position we had for
6462    * the previous redraw since we don't know where to set the clip so
6463    * it will clear the actor as it is currently.
6464    */
6465   if (clip)
6466     {
6467       _clutter_actor_set_queue_redraw_clip (self, clip);
6468       clipped = TRUE;
6469     }
6470   else if (G_LIKELY (priv->last_paint_volume_valid))
6471     {
6472       pv = _clutter_actor_get_paint_volume_mutable (self);
6473       if (pv)
6474         {
6475           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6476
6477           /* make sure we redraw the actors old position... */
6478           _clutter_actor_set_queue_redraw_clip (stage,
6479                                                 &priv->last_paint_volume);
6480           _clutter_actor_signal_queue_redraw (stage, stage);
6481           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6482
6483           /* XXX: Ideally the redraw signal would take a clip volume
6484            * argument, but that would be an ABI break. Until we can
6485            * break the ABI we pass the argument out-of-band
6486            */
6487
6488           /* setup the clip for the actors new position... */
6489           _clutter_actor_set_queue_redraw_clip (self, pv);
6490           clipped = TRUE;
6491         }
6492       else
6493         clipped = FALSE;
6494     }
6495   else
6496     clipped = FALSE;
6497
6498   _clutter_actor_signal_queue_redraw (self, self);
6499
6500   /* Just in case anyone is manually firing redraw signals without
6501    * using the public queue_redraw() API we are careful to ensure that
6502    * our out-of-band clip member is cleared before returning...
6503    *
6504    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6505    */
6506   if (G_LIKELY (clipped))
6507     _clutter_actor_set_queue_redraw_clip (self, NULL);
6508
6509   priv->queue_redraw_entry = NULL;
6510 }
6511
6512 static void
6513 _clutter_actor_get_allocation_clip (ClutterActor *self,
6514                                     ClutterActorBox *clip)
6515 {
6516   ClutterActorBox allocation;
6517
6518   /* XXX: we don't care if we get an out of date allocation here
6519    * because clutter_actor_queue_redraw_with_clip knows to ignore
6520    * the clip if the actor's allocation is invalid.
6521    *
6522    * This is noted because clutter_actor_get_allocation_box does some
6523    * unnecessary work to support buggy code with a comment suggesting
6524    * that it could be changed later which would be good for this use
6525    * case!
6526    */
6527   clutter_actor_get_allocation_box (self, &allocation);
6528
6529   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6530    * actor's own coordinate space but the allocation is in parent
6531    * coordinates */
6532   clip->x1 = 0;
6533   clip->y1 = 0;
6534   clip->x2 = allocation.x2 - allocation.x1;
6535   clip->y2 = allocation.y2 - allocation.y1;
6536 }
6537
6538 void
6539 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6540                                   ClutterRedrawFlags  flags,
6541                                   ClutterPaintVolume *volume,
6542                                   ClutterEffect      *effect)
6543 {
6544   ClutterActorPrivate *priv = self->priv;
6545   ClutterPaintVolume allocation_pv;
6546   ClutterPaintVolume *pv;
6547   gboolean should_free_pv;
6548   ClutterActor *stage;
6549
6550   /* Here's an outline of the actor queue redraw mechanism:
6551    *
6552    * The process starts in one of the following two functions which
6553    * are wrappers for this function:
6554    * clutter_actor_queue_redraw
6555    * _clutter_actor_queue_redraw_with_clip
6556    *
6557    * additionally, an effect can queue a redraw by wrapping this
6558    * function in clutter_effect_queue_rerun
6559    *
6560    * This functions queues an entry in a list associated with the
6561    * stage which is a list of actors that queued a redraw while
6562    * updating the timelines, performing layouting and processing other
6563    * mainloop sources before the next paint starts.
6564    *
6565    * We aim to minimize the processing done at this point because
6566    * there is a good chance other events will happen while updating
6567    * the scenegraph that would invalidate any expensive work we might
6568    * otherwise try to do here. For example we don't try and resolve
6569    * the screen space bounding box of an actor at this stage so as to
6570    * minimize how much of the screen redraw because it's possible
6571    * something else will happen which will force a full redraw anyway.
6572    *
6573    * When all updates are complete and we come to paint the stage then
6574    * we iterate this list and actually emit the "queue-redraw" signals
6575    * for each of the listed actors which will bubble up to the stage
6576    * for each actor and at that point we will transform the actors
6577    * paint volume into screen coordinates to determine the clip region
6578    * for what needs to be redrawn in the next paint.
6579    *
6580    * Besides minimizing redundant work another reason for this
6581    * deferred design is that it's more likely we will be able to
6582    * determine the paint volume of an actor once we've finished
6583    * updating the scenegraph because its allocation should be up to
6584    * date. NB: If we can't determine an actors paint volume then we
6585    * can't automatically queue a clipped redraw which can make a big
6586    * difference to performance.
6587    *
6588    * So the control flow goes like this:
6589    * One of clutter_actor_queue_redraw,
6590    *        _clutter_actor_queue_redraw_with_clip
6591    *     or clutter_effect_queue_rerun
6592    *
6593    * then control moves to:
6594    *   _clutter_stage_queue_actor_redraw
6595    *
6596    * later during _clutter_stage_do_update, once relayouting is done
6597    * and the scenegraph has been updated we will call:
6598    * _clutter_stage_finish_queue_redraws
6599    *
6600    * _clutter_stage_finish_queue_redraws will call
6601    * _clutter_actor_finish_queue_redraw for each listed actor.
6602    * Note: actors *are* allowed to queue further redraws during this
6603    * process (considering clone actors or texture_new_from_actor which
6604    * respond to their source queueing a redraw by queuing a redraw
6605    * themselves). We repeat the process until the list is empty.
6606    *
6607    * This will result in the "queue-redraw" signal being fired for
6608    * each actor which will pass control to the default signal handler:
6609    * clutter_actor_real_queue_redraw
6610    *
6611    * This will bubble up to the stages handler:
6612    * clutter_stage_real_queue_redraw
6613    *
6614    * clutter_stage_real_queue_redraw will transform the actors paint
6615    * volume into screen space and add it as a clip region for the next
6616    * paint.
6617    */
6618
6619   /* ignore queueing a redraw for actors being destroyed */
6620   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6621     return;
6622
6623   stage = _clutter_actor_get_stage_internal (self);
6624
6625   /* Ignore queueing a redraw for actors not descended from a stage */
6626   if (stage == NULL)
6627     return;
6628
6629   /* ignore queueing a redraw on stages that are being destroyed */
6630   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6631     return;
6632
6633   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6634     {
6635       ClutterActorBox allocation_clip;
6636       ClutterVertex origin;
6637
6638       /* If the actor doesn't have a valid allocation then we will
6639        * queue a full stage redraw. */
6640       if (priv->needs_allocation)
6641         {
6642           /* NB: NULL denotes an undefined clip which will result in a
6643            * full redraw... */
6644           _clutter_actor_set_queue_redraw_clip (self, NULL);
6645           _clutter_actor_signal_queue_redraw (self, self);
6646           return;
6647         }
6648
6649       _clutter_paint_volume_init_static (&allocation_pv, self);
6650       pv = &allocation_pv;
6651
6652       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6653
6654       origin.x = allocation_clip.x1;
6655       origin.y = allocation_clip.y1;
6656       origin.z = 0;
6657       clutter_paint_volume_set_origin (pv, &origin);
6658       clutter_paint_volume_set_width (pv,
6659                                       allocation_clip.x2 - allocation_clip.x1);
6660       clutter_paint_volume_set_height (pv,
6661                                        allocation_clip.y2 -
6662                                        allocation_clip.y1);
6663       should_free_pv = TRUE;
6664     }
6665   else
6666     {
6667       pv = volume;
6668       should_free_pv = FALSE;
6669     }
6670
6671   self->priv->queue_redraw_entry =
6672     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6673                                        priv->queue_redraw_entry,
6674                                        self,
6675                                        pv);
6676
6677   if (should_free_pv)
6678     clutter_paint_volume_free (pv);
6679
6680   /* If this is the first redraw queued then we can directly use the
6681      effect parameter */
6682   if (!priv->is_dirty)
6683     priv->effect_to_redraw = effect;
6684   /* Otherwise we need to merge it with the existing effect parameter */
6685   else if (effect != NULL)
6686     {
6687       /* If there's already an effect then we need to use whichever is
6688          later in the chain of actors. Otherwise a full redraw has
6689          already been queued on the actor so we need to ignore the
6690          effect parameter */
6691       if (priv->effect_to_redraw != NULL)
6692         {
6693           if (priv->effects == NULL)
6694             g_warning ("Redraw queued with an effect that is "
6695                        "not applied to the actor");
6696           else
6697             {
6698               const GList *l;
6699
6700               for (l = _clutter_meta_group_peek_metas (priv->effects);
6701                    l != NULL;
6702                    l = l->next)
6703                 {
6704                   if (l->data == priv->effect_to_redraw ||
6705                       l->data == effect)
6706                     priv->effect_to_redraw = l->data;
6707                 }
6708             }
6709         }
6710     }
6711   else
6712     {
6713       /* If no effect is specified then we need to redraw the whole
6714          actor */
6715       priv->effect_to_redraw = NULL;
6716     }
6717
6718   priv->is_dirty = TRUE;
6719 }
6720
6721 /**
6722  * clutter_actor_queue_redraw:
6723  * @self: A #ClutterActor
6724  *
6725  * Queues up a redraw of an actor and any children. The redraw occurs
6726  * once the main loop becomes idle (after the current batch of events
6727  * has been processed, roughly).
6728  *
6729  * Applications rarely need to call this, as redraws are handled
6730  * automatically by modification functions.
6731  *
6732  * This function will not do anything if @self is not visible, or
6733  * if the actor is inside an invisible part of the scenegraph.
6734  *
6735  * Also be aware that painting is a NOP for actors with an opacity of
6736  * 0
6737  *
6738  * When you are implementing a custom actor you must queue a redraw
6739  * whenever some private state changes that will affect painting or
6740  * picking of your actor.
6741  */
6742 void
6743 clutter_actor_queue_redraw (ClutterActor *self)
6744 {
6745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6746
6747   _clutter_actor_queue_redraw_full (self,
6748                                     0, /* flags */
6749                                     NULL, /* clip volume */
6750                                     NULL /* effect */);
6751 }
6752
6753 /*< private >
6754  * _clutter_actor_queue_redraw_with_clip:
6755  * @self: A #ClutterActor
6756  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6757  *   this queue redraw.
6758  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6759  *   redrawn or %NULL if you are just using a @flag to state your
6760  *   desired clipping.
6761  *
6762  * Queues up a clipped redraw of an actor and any children. The redraw
6763  * occurs once the main loop becomes idle (after the current batch of
6764  * events has been processed, roughly).
6765  *
6766  * If no flags are given the clip volume is defined by @volume
6767  * specified in actor coordinates and tells Clutter that only content
6768  * within this volume has been changed so Clutter can optionally
6769  * optimize the redraw.
6770  *
6771  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6772  * should be %NULL and this tells Clutter to use the actor's current
6773  * allocation as a clip box. This flag can only be used for 2D actors,
6774  * because any actor with depth may be projected outside its
6775  * allocation.
6776  *
6777  * Applications rarely need to call this, as redraws are handled
6778  * automatically by modification functions.
6779  *
6780  * This function will not do anything if @self is not visible, or if
6781  * the actor is inside an invisible part of the scenegraph.
6782  *
6783  * Also be aware that painting is a NOP for actors with an opacity of
6784  * 0
6785  *
6786  * When you are implementing a custom actor you must queue a redraw
6787  * whenever some private state changes that will affect painting or
6788  * picking of your actor.
6789  */
6790 void
6791 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6792                                        ClutterRedrawFlags  flags,
6793                                        ClutterPaintVolume *volume)
6794 {
6795   _clutter_actor_queue_redraw_full (self,
6796                                     flags, /* flags */
6797                                     volume, /* clip volume */
6798                                     NULL /* effect */);
6799 }
6800
6801 static void
6802 _clutter_actor_queue_only_relayout (ClutterActor *self)
6803 {
6804   ClutterActorPrivate *priv = self->priv;
6805
6806   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6807     return;
6808
6809   if (priv->needs_width_request &&
6810       priv->needs_height_request &&
6811       priv->needs_allocation)
6812     return; /* save some cpu cycles */
6813
6814 #if CLUTTER_ENABLE_DEBUG
6815   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6816     {
6817       g_warning ("The actor '%s' is currently inside an allocation "
6818                  "cycle; calling clutter_actor_queue_relayout() is "
6819                  "not recommended",
6820                  _clutter_actor_get_debug_name (self));
6821     }
6822 #endif /* CLUTTER_ENABLE_DEBUG */
6823
6824   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6825 }
6826
6827 /**
6828  * clutter_actor_queue_redraw_with_clip:
6829  * @self: a #ClutterActor
6830  * @clip: (allow-none): a rectangular clip region, or %NULL
6831  *
6832  * Queues a redraw on @self limited to a specific, actor-relative
6833  * rectangular area.
6834  *
6835  * If @clip is %NULL this function is equivalent to
6836  * clutter_actor_queue_redraw().
6837  *
6838  * Since: 1.10
6839  */
6840 void
6841 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6842                                       const cairo_rectangle_int_t *clip)
6843 {
6844   ClutterPaintVolume volume;
6845   ClutterVertex origin;
6846
6847   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6848
6849   if (clip == NULL)
6850     {
6851       clutter_actor_queue_redraw (self);
6852       return;
6853     }
6854
6855   _clutter_paint_volume_init_static (&volume, self);
6856
6857   origin.x = clip->x;
6858   origin.y = clip->y;
6859   origin.z = 0.0f;
6860
6861   clutter_paint_volume_set_origin (&volume, &origin);
6862   clutter_paint_volume_set_width (&volume, clip->width);
6863   clutter_paint_volume_set_height (&volume, clip->height);
6864
6865   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6866
6867   clutter_paint_volume_free (&volume);
6868 }
6869
6870 /**
6871  * clutter_actor_queue_relayout:
6872  * @self: A #ClutterActor
6873  *
6874  * Indicates that the actor's size request or other layout-affecting
6875  * properties may have changed. This function is used inside #ClutterActor
6876  * subclass implementations, not by applications directly.
6877  *
6878  * Queueing a new layout automatically queues a redraw as well.
6879  *
6880  * Since: 0.8
6881  */
6882 void
6883 clutter_actor_queue_relayout (ClutterActor *self)
6884 {
6885   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6886
6887   _clutter_actor_queue_only_relayout (self);
6888   clutter_actor_queue_redraw (self);
6889 }
6890
6891 /**
6892  * clutter_actor_get_preferred_size:
6893  * @self: a #ClutterActor
6894  * @min_width_p: (out) (allow-none): return location for the minimum
6895  *   width, or %NULL
6896  * @min_height_p: (out) (allow-none): return location for the minimum
6897  *   height, or %NULL
6898  * @natural_width_p: (out) (allow-none): return location for the natural
6899  *   width, or %NULL
6900  * @natural_height_p: (out) (allow-none): return location for the natural
6901  *   height, or %NULL
6902  *
6903  * Computes the preferred minimum and natural size of an actor, taking into
6904  * account the actor's geometry management (either height-for-width
6905  * or width-for-height).
6906  *
6907  * The width and height used to compute the preferred height and preferred
6908  * width are the actor's natural ones.
6909  *
6910  * If you need to control the height for the preferred width, or the width for
6911  * the preferred height, you should use clutter_actor_get_preferred_width()
6912  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6913  * geometry management using the #ClutterActor:request-mode property.
6914  *
6915  * Since: 0.8
6916  */
6917 void
6918 clutter_actor_get_preferred_size (ClutterActor *self,
6919                                   gfloat       *min_width_p,
6920                                   gfloat       *min_height_p,
6921                                   gfloat       *natural_width_p,
6922                                   gfloat       *natural_height_p)
6923 {
6924   ClutterActorPrivate *priv;
6925   gfloat min_width, min_height;
6926   gfloat natural_width, natural_height;
6927
6928   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6929
6930   priv = self->priv;
6931
6932   min_width = min_height = 0;
6933   natural_width = natural_height = 0;
6934
6935   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6936     {
6937       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6938       clutter_actor_get_preferred_width (self, -1,
6939                                          &min_width,
6940                                          &natural_width);
6941       clutter_actor_get_preferred_height (self, natural_width,
6942                                           &min_height,
6943                                           &natural_height);
6944     }
6945   else
6946     {
6947       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6948       clutter_actor_get_preferred_height (self, -1,
6949                                           &min_height,
6950                                           &natural_height);
6951       clutter_actor_get_preferred_width (self, natural_height,
6952                                          &min_width,
6953                                          &natural_width);
6954     }
6955
6956   if (min_width_p)
6957     *min_width_p = min_width;
6958
6959   if (min_height_p)
6960     *min_height_p = min_height;
6961
6962   if (natural_width_p)
6963     *natural_width_p = natural_width;
6964
6965   if (natural_height_p)
6966     *natural_height_p = natural_height;
6967 }
6968
6969 /*< private >
6970  * effective_align:
6971  * @align: a #ClutterActorAlign
6972  * @direction: a #ClutterTextDirection
6973  *
6974  * Retrieves the correct alignment depending on the text direction
6975  *
6976  * Return value: the effective alignment
6977  */
6978 static ClutterActorAlign
6979 effective_align (ClutterActorAlign    align,
6980                  ClutterTextDirection direction)
6981 {
6982   ClutterActorAlign res;
6983
6984   switch (align)
6985     {
6986     case CLUTTER_ACTOR_ALIGN_START:
6987       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6988           ? CLUTTER_ACTOR_ALIGN_END
6989           : CLUTTER_ACTOR_ALIGN_START;
6990       break;
6991
6992     case CLUTTER_ACTOR_ALIGN_END:
6993       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6994           ? CLUTTER_ACTOR_ALIGN_START
6995           : CLUTTER_ACTOR_ALIGN_END;
6996       break;
6997
6998     default:
6999       res = align;
7000       break;
7001     }
7002
7003   return res;
7004 }
7005
7006 static inline void
7007 adjust_for_margin (float  margin_start,
7008                    float  margin_end,
7009                    float *minimum_size,
7010                    float *natural_size,
7011                    float *allocated_start,
7012                    float *allocated_end)
7013 {
7014   *minimum_size -= (margin_start + margin_end);
7015   *natural_size -= (margin_start + margin_end);
7016   *allocated_start += margin_start;
7017   *allocated_end -= margin_end;
7018 }
7019
7020 static inline void
7021 adjust_for_alignment (ClutterActorAlign  alignment,
7022                       float              natural_size,
7023                       float             *allocated_start,
7024                       float             *allocated_end)
7025 {
7026   float allocated_size = *allocated_end - *allocated_start;
7027
7028   switch (alignment)
7029     {
7030     case CLUTTER_ACTOR_ALIGN_FILL:
7031       /* do nothing */
7032       break;
7033
7034     case CLUTTER_ACTOR_ALIGN_START:
7035       /* keep start */
7036       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7037       break;
7038
7039     case CLUTTER_ACTOR_ALIGN_END:
7040       if (allocated_size > natural_size)
7041         {
7042           *allocated_start += (allocated_size - natural_size);
7043           *allocated_end = *allocated_start + natural_size;
7044         }
7045       break;
7046
7047     case CLUTTER_ACTOR_ALIGN_CENTER:
7048       if (allocated_size > natural_size)
7049         {
7050           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7051           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7052         }
7053       break;
7054     }
7055 }
7056
7057 /*< private >
7058  * clutter_actor_adjust_width:
7059  * @self: a #ClutterActor
7060  * @minimum_width: (inout): the actor's preferred minimum width, which
7061  *   will be adjusted depending on the margin
7062  * @natural_width: (inout): the actor's preferred natural width, which
7063  *   will be adjusted depending on the margin
7064  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7065  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7066  *
7067  * Adjusts the preferred and allocated position and size of an actor,
7068  * depending on the margin and alignment properties.
7069  */
7070 static void
7071 clutter_actor_adjust_width (ClutterActor *self,
7072                             gfloat       *minimum_width,
7073                             gfloat       *natural_width,
7074                             gfloat       *adjusted_x1,
7075                             gfloat       *adjusted_x2)
7076 {
7077   ClutterTextDirection text_dir;
7078   const ClutterLayoutInfo *info;
7079
7080   info = _clutter_actor_get_layout_info_or_defaults (self);
7081   text_dir = clutter_actor_get_text_direction (self);
7082
7083   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7084
7085   /* this will tweak natural_width to remove the margin, so that
7086    * adjust_for_alignment() will use the correct size
7087    */
7088   adjust_for_margin (info->margin.left, info->margin.right,
7089                      minimum_width, natural_width,
7090                      adjusted_x1, adjusted_x2);
7091
7092   adjust_for_alignment (effective_align (info->x_align, text_dir),
7093                         *natural_width,
7094                         adjusted_x1, adjusted_x2);
7095 }
7096
7097 /*< private >
7098  * clutter_actor_adjust_height:
7099  * @self: a #ClutterActor
7100  * @minimum_height: (inout): the actor's preferred minimum height, which
7101  *   will be adjusted depending on the margin
7102  * @natural_height: (inout): the actor's preferred natural height, which
7103  *   will be adjusted depending on the margin
7104  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7105  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7106  *
7107  * Adjusts the preferred and allocated position and size of an actor,
7108  * depending on the margin and alignment properties.
7109  */
7110 static void
7111 clutter_actor_adjust_height (ClutterActor *self,
7112                              gfloat       *minimum_height,
7113                              gfloat       *natural_height,
7114                              gfloat       *adjusted_y1,
7115                              gfloat       *adjusted_y2)
7116 {
7117   const ClutterLayoutInfo *info;
7118
7119   info = _clutter_actor_get_layout_info_or_defaults (self);
7120
7121   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7122
7123   /* this will tweak natural_height to remove the margin, so that
7124    * adjust_for_alignment() will use the correct size
7125    */
7126   adjust_for_margin (info->margin.top, info->margin.bottom,
7127                      minimum_height, natural_height,
7128                      adjusted_y1,
7129                      adjusted_y2);
7130
7131   /* we don't use effective_align() here, because text direction
7132    * only affects the horizontal axis
7133    */
7134   adjust_for_alignment (info->y_align,
7135                         *natural_height,
7136                         adjusted_y1,
7137                         adjusted_y2);
7138
7139 }
7140
7141 /* looks for a cached size request for this for_size. If not
7142  * found, returns the oldest entry so it can be overwritten */
7143 static gboolean
7144 _clutter_actor_get_cached_size_request (gfloat         for_size,
7145                                         SizeRequest   *cached_size_requests,
7146                                         SizeRequest  **result)
7147 {
7148   guint i;
7149
7150   *result = &cached_size_requests[0];
7151
7152   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7153     {
7154       SizeRequest *sr;
7155
7156       sr = &cached_size_requests[i];
7157
7158       if (sr->age > 0 &&
7159           sr->for_size == for_size)
7160         {
7161           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7162           *result = sr;
7163           return TRUE;
7164         }
7165       else if (sr->age < (*result)->age)
7166         {
7167           *result = sr;
7168         }
7169     }
7170
7171   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7172
7173   return FALSE;
7174 }
7175
7176 /**
7177  * clutter_actor_get_preferred_width:
7178  * @self: A #ClutterActor
7179  * @for_height: available height when computing the preferred width,
7180  *   or a negative value to indicate that no height is defined
7181  * @min_width_p: (out) (allow-none): return location for minimum width,
7182  *   or %NULL
7183  * @natural_width_p: (out) (allow-none): return location for the natural
7184  *   width, or %NULL
7185  *
7186  * Computes the requested minimum and natural widths for an actor,
7187  * optionally depending on the specified height, or if they are
7188  * already computed, returns the cached values.
7189  *
7190  * An actor may not get its request - depending on the layout
7191  * manager that's in effect.
7192  *
7193  * A request should not incorporate the actor's scale or anchor point;
7194  * those transformations do not affect layout, only rendering.
7195  *
7196  * Since: 0.8
7197  */
7198 void
7199 clutter_actor_get_preferred_width (ClutterActor *self,
7200                                    gfloat        for_height,
7201                                    gfloat       *min_width_p,
7202                                    gfloat       *natural_width_p)
7203 {
7204   float request_min_width, request_natural_width;
7205   SizeRequest *cached_size_request;
7206   const ClutterLayoutInfo *info;
7207   ClutterActorPrivate *priv;
7208   gboolean found_in_cache;
7209
7210   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7211
7212   priv = self->priv;
7213
7214   info = _clutter_actor_get_layout_info_or_defaults (self);
7215
7216   /* we shortcircuit the case of a fixed size set using set_width() */
7217   if (priv->min_width_set && priv->natural_width_set)
7218     {
7219       if (min_width_p != NULL)
7220         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7221
7222       if (natural_width_p != NULL)
7223         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7224
7225       return;
7226     }
7227
7228   /* the remaining cases are:
7229    *
7230    *   - either min_width or natural_width have been set
7231    *   - neither min_width or natural_width have been set
7232    *
7233    * in both cases, we go through the cache (and through the actor in case
7234    * of cache misses) and determine the authoritative value depending on
7235    * the *_set flags.
7236    */
7237
7238   if (!priv->needs_width_request)
7239     {
7240       found_in_cache =
7241         _clutter_actor_get_cached_size_request (for_height,
7242                                                 priv->width_requests,
7243                                                 &cached_size_request);
7244     }
7245   else
7246     {
7247       /* if the actor needs a width request we use the first slot */
7248       found_in_cache = FALSE;
7249       cached_size_request = &priv->width_requests[0];
7250     }
7251
7252   if (!found_in_cache)
7253     {
7254       gfloat minimum_width, natural_width;
7255       ClutterActorClass *klass;
7256
7257       minimum_width = natural_width = 0;
7258
7259       /* adjust for the margin */
7260       if (for_height >= 0)
7261         {
7262           for_height -= (info->margin.top + info->margin.bottom);
7263           if (for_height < 0)
7264             for_height = 0;
7265         }
7266
7267       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7268
7269       klass = CLUTTER_ACTOR_GET_CLASS (self);
7270       klass->get_preferred_width (self, for_height,
7271                                   &minimum_width,
7272                                   &natural_width);
7273
7274       /* adjust for the margin */
7275       minimum_width += (info->margin.left + info->margin.right);
7276       natural_width += (info->margin.left + info->margin.right);
7277
7278       /* Due to accumulated float errors, it's better not to warn
7279        * on this, but just fix it.
7280        */
7281       if (natural_width < minimum_width)
7282         natural_width = minimum_width;
7283
7284       cached_size_request->min_size = minimum_width;
7285       cached_size_request->natural_size = natural_width;
7286       cached_size_request->for_size = for_height;
7287       cached_size_request->age = priv->cached_width_age;
7288
7289       priv->cached_width_age += 1;
7290       priv->needs_width_request = FALSE;
7291     }
7292
7293   if (!priv->min_width_set)
7294     request_min_width = cached_size_request->min_size;
7295   else
7296     request_min_width = info->min_width;
7297
7298   if (!priv->natural_width_set)
7299     request_natural_width = cached_size_request->natural_size;
7300   else
7301     request_natural_width = info->natural_width;
7302
7303   if (min_width_p)
7304     *min_width_p = request_min_width;
7305
7306   if (natural_width_p)
7307     *natural_width_p = request_natural_width;
7308 }
7309
7310 /**
7311  * clutter_actor_get_preferred_height:
7312  * @self: A #ClutterActor
7313  * @for_width: available width to assume in computing desired height,
7314  *   or a negative value to indicate that no width is defined
7315  * @min_height_p: (out) (allow-none): return location for minimum height,
7316  *   or %NULL
7317  * @natural_height_p: (out) (allow-none): return location for natural
7318  *   height, or %NULL
7319  *
7320  * Computes the requested minimum and natural heights for an actor,
7321  * or if they are already computed, returns the cached values.
7322  *
7323  * An actor may not get its request - depending on the layout
7324  * manager that's in effect.
7325  *
7326  * A request should not incorporate the actor's scale or anchor point;
7327  * those transformations do not affect layout, only rendering.
7328  *
7329  * Since: 0.8
7330  */
7331 void
7332 clutter_actor_get_preferred_height (ClutterActor *self,
7333                                     gfloat        for_width,
7334                                     gfloat       *min_height_p,
7335                                     gfloat       *natural_height_p)
7336 {
7337   float request_min_height, request_natural_height;
7338   SizeRequest *cached_size_request;
7339   const ClutterLayoutInfo *info;
7340   ClutterActorPrivate *priv;
7341   gboolean found_in_cache;
7342
7343   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7344
7345   priv = self->priv;
7346
7347   info = _clutter_actor_get_layout_info_or_defaults (self);
7348
7349   /* we shortcircuit the case of a fixed size set using set_height() */
7350   if (priv->min_height_set && priv->natural_height_set)
7351     {
7352       if (min_height_p != NULL)
7353         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7354
7355       if (natural_height_p != NULL)
7356         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7357
7358       return;
7359     }
7360
7361   /* the remaining cases are:
7362    *
7363    *   - either min_height or natural_height have been set
7364    *   - neither min_height or natural_height have been set
7365    *
7366    * in both cases, we go through the cache (and through the actor in case
7367    * of cache misses) and determine the authoritative value depending on
7368    * the *_set flags.
7369    */
7370
7371   if (!priv->needs_height_request)
7372     {
7373       found_in_cache =
7374         _clutter_actor_get_cached_size_request (for_width,
7375                                                 priv->height_requests,
7376                                                 &cached_size_request);
7377     }
7378   else
7379     {
7380       found_in_cache = FALSE;
7381       cached_size_request = &priv->height_requests[0];
7382     }
7383
7384   if (!found_in_cache)
7385     {
7386       gfloat minimum_height, natural_height;
7387       ClutterActorClass *klass;
7388
7389       minimum_height = natural_height = 0;
7390
7391       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7392
7393       /* adjust for margin */
7394       if (for_width >= 0)
7395         {
7396           for_width -= (info->margin.left + info->margin.right);
7397           if (for_width < 0)
7398             for_width = 0;
7399         }
7400
7401       klass = CLUTTER_ACTOR_GET_CLASS (self);
7402       klass->get_preferred_height (self, for_width,
7403                                    &minimum_height,
7404                                    &natural_height);
7405
7406       /* adjust for margin */
7407       minimum_height += (info->margin.top + info->margin.bottom);
7408       natural_height += (info->margin.top + info->margin.bottom);
7409
7410       /* Due to accumulated float errors, it's better not to warn
7411        * on this, but just fix it.
7412        */
7413       if (natural_height < minimum_height)
7414         natural_height = minimum_height;
7415
7416       cached_size_request->min_size = minimum_height;
7417       cached_size_request->natural_size = natural_height;
7418       cached_size_request->for_size = for_width;
7419       cached_size_request->age = priv->cached_height_age;
7420
7421       priv->cached_height_age += 1;
7422       priv->needs_height_request = FALSE;
7423     }
7424
7425   if (!priv->min_height_set)
7426     request_min_height = cached_size_request->min_size;
7427   else
7428     request_min_height = info->min_height;
7429
7430   if (!priv->natural_height_set)
7431     request_natural_height = cached_size_request->natural_size;
7432   else
7433     request_natural_height = info->natural_height;
7434
7435   if (min_height_p)
7436     *min_height_p = request_min_height;
7437
7438   if (natural_height_p)
7439     *natural_height_p = request_natural_height;
7440 }
7441
7442 /**
7443  * clutter_actor_get_allocation_box:
7444  * @self: A #ClutterActor
7445  * @box: (out): the function fills this in with the actor's allocation
7446  *
7447  * Gets the layout box an actor has been assigned. The allocation can
7448  * only be assumed valid inside a paint() method; anywhere else, it
7449  * may be out-of-date.
7450  *
7451  * An allocation does not incorporate the actor's scale or anchor point;
7452  * those transformations do not affect layout, only rendering.
7453  *
7454  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7455  * of functions inside the implementation of the get_preferred_width()
7456  * or get_preferred_height() virtual functions.</note>
7457  *
7458  * Since: 0.8
7459  */
7460 void
7461 clutter_actor_get_allocation_box (ClutterActor    *self,
7462                                   ClutterActorBox *box)
7463 {
7464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7465
7466   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7467    * which limits calling get_allocation to inside paint() basically; or
7468    * we can 2) force a layout, which could be expensive if someone calls
7469    * get_allocation somewhere silly; or we can 3) just return the latest
7470    * value, allowing it to be out-of-date, and assume people know what
7471    * they are doing.
7472    *
7473    * The least-surprises approach that keeps existing code working is
7474    * likely to be 2). People can end up doing some inefficient things,
7475    * though, and in general code that requires 2) is probably broken.
7476    */
7477
7478   /* this implements 2) */
7479   if (G_UNLIKELY (self->priv->needs_allocation))
7480     {
7481       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7482
7483       /* do not queue a relayout on an unparented actor */
7484       if (stage)
7485         _clutter_stage_maybe_relayout (stage);
7486     }
7487
7488   /* commenting out the code above and just keeping this assigment
7489    * implements 3)
7490    */
7491   *box = self->priv->allocation;
7492 }
7493
7494 /**
7495  * clutter_actor_get_allocation_geometry:
7496  * @self: A #ClutterActor
7497  * @geom: (out): allocation geometry in pixels
7498  *
7499  * Gets the layout box an actor has been assigned.  The allocation can
7500  * only be assumed valid inside a paint() method; anywhere else, it
7501  * may be out-of-date.
7502  *
7503  * An allocation does not incorporate the actor's scale or anchor point;
7504  * those transformations do not affect layout, only rendering.
7505  *
7506  * The returned rectangle is in pixels.
7507  *
7508  * Since: 0.8
7509  */
7510 void
7511 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7512                                        ClutterGeometry *geom)
7513 {
7514   ClutterActorBox box;
7515
7516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7517   g_return_if_fail (geom != NULL);
7518
7519   clutter_actor_get_allocation_box (self, &box);
7520
7521   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7522   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7523   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7524   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7525 }
7526
7527 static void
7528 clutter_actor_update_constraints (ClutterActor    *self,
7529                                   ClutterActorBox *allocation)
7530 {
7531   ClutterActorPrivate *priv = self->priv;
7532   const GList *constraints, *l;
7533
7534   if (priv->constraints == NULL)
7535     return;
7536
7537   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7538   for (l = constraints; l != NULL; l = l->next)
7539     {
7540       ClutterConstraint *constraint = l->data;
7541       ClutterActorMeta *meta = l->data;
7542
7543       if (clutter_actor_meta_get_enabled (meta))
7544         {
7545           _clutter_constraint_update_allocation (constraint,
7546                                                  self,
7547                                                  allocation);
7548         }
7549     }
7550 }
7551
7552 /*< private >
7553  * clutter_actor_adjust_allocation:
7554  * @self: a #ClutterActor
7555  * @allocation: (inout): the allocation to adjust
7556  *
7557  * Adjusts the passed allocation box taking into account the actor's
7558  * layout information, like alignment, expansion, and margin.
7559  */
7560 static void
7561 clutter_actor_adjust_allocation (ClutterActor    *self,
7562                                  ClutterActorBox *allocation)
7563 {
7564   ClutterActorBox adj_allocation;
7565   float alloc_width, alloc_height;
7566   float min_width, min_height;
7567   float nat_width, nat_height;
7568   ClutterRequestMode req_mode;
7569
7570   adj_allocation = *allocation;
7571
7572   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7573
7574   /* we want to hit the cache, so we use the public API */
7575   req_mode = clutter_actor_get_request_mode (self);
7576
7577   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7578     {
7579       clutter_actor_get_preferred_width (self, -1,
7580                                          &min_width,
7581                                          &nat_width);
7582       clutter_actor_get_preferred_height (self, alloc_width,
7583                                           &min_height,
7584                                           &nat_height);
7585     }
7586   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7587     {
7588       clutter_actor_get_preferred_height (self, -1,
7589                                           &min_height,
7590                                           &nat_height);
7591       clutter_actor_get_preferred_height (self, alloc_height,
7592                                           &min_width,
7593                                           &nat_width);
7594     }
7595
7596 #ifdef CLUTTER_ENABLE_DEBUG
7597   /* warn about underallocations */
7598   if (_clutter_diagnostic_enabled () &&
7599       (floorf (min_width - alloc_width) > 0 ||
7600        floorf (min_height - alloc_height) > 0))
7601     {
7602       ClutterActor *parent = clutter_actor_get_parent (self);
7603
7604       /* the only actors that are allowed to be underallocated are the Stage,
7605        * as it doesn't have an implicit size, and Actors that specifically
7606        * told us that they want to opt-out from layout control mechanisms
7607        * through the NO_LAYOUT escape hatch.
7608        */
7609       if (parent != NULL &&
7610           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7611         {
7612           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7613                      "of %.2f x %.2f from its parent actor '%s', but its "
7614                      "requested minimum size is of %.2f x %.2f",
7615                      _clutter_actor_get_debug_name (self),
7616                      alloc_width, alloc_height,
7617                      _clutter_actor_get_debug_name (parent),
7618                      min_width, min_height);
7619         }
7620     }
7621 #endif
7622
7623   clutter_actor_adjust_width (self,
7624                               &min_width,
7625                               &nat_width,
7626                               &adj_allocation.x1,
7627                               &adj_allocation.x2);
7628
7629   clutter_actor_adjust_height (self,
7630                                &min_height,
7631                                &nat_height,
7632                                &adj_allocation.y1,
7633                                &adj_allocation.y2);
7634
7635   /* we maintain the invariant that an allocation cannot be adjusted
7636    * to be outside the parent-given box
7637    */
7638   if (adj_allocation.x1 < allocation->x1 ||
7639       adj_allocation.y1 < allocation->y1 ||
7640       adj_allocation.x2 > allocation->x2 ||
7641       adj_allocation.y2 > allocation->y2)
7642     {
7643       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7644                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7645                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7646                  _clutter_actor_get_debug_name (self),
7647                  adj_allocation.x1, adj_allocation.y1,
7648                  adj_allocation.x2 - adj_allocation.x1,
7649                  adj_allocation.y2 - adj_allocation.y1,
7650                  allocation->x1, allocation->y1,
7651                  allocation->x2 - allocation->x1,
7652                  allocation->y2 - allocation->y1);
7653       return;
7654     }
7655
7656   *allocation = adj_allocation;
7657 }
7658
7659 /**
7660  * clutter_actor_allocate:
7661  * @self: A #ClutterActor
7662  * @box: new allocation of the actor, in parent-relative coordinates
7663  * @flags: flags that control the allocation
7664  *
7665  * Called by the parent of an actor to assign the actor its size.
7666  * Should never be called by applications (except when implementing
7667  * a container or layout manager).
7668  *
7669  * Actors can know from their allocation box whether they have moved
7670  * with respect to their parent actor. The @flags parameter describes
7671  * additional information about the allocation, for instance whether
7672  * the parent has moved with respect to the stage, for example because
7673  * a grandparent's origin has moved.
7674  *
7675  * Since: 0.8
7676  */
7677 void
7678 clutter_actor_allocate (ClutterActor           *self,
7679                         const ClutterActorBox  *box,
7680                         ClutterAllocationFlags  flags)
7681 {
7682   ClutterActorPrivate *priv;
7683   ClutterActorClass *klass;
7684   ClutterActorBox old_allocation, real_allocation;
7685   gboolean origin_changed, child_moved, size_changed;
7686   gboolean stage_allocation_changed;
7687
7688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7689   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7690     {
7691       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7692                  "which isn't a descendent of the stage!\n",
7693                  self, _clutter_actor_get_debug_name (self));
7694       return;
7695     }
7696
7697   priv = self->priv;
7698
7699   old_allocation = priv->allocation;
7700   real_allocation = *box;
7701
7702   /* constraints are allowed to modify the allocation only here; we do
7703    * this prior to all the other checks so that we can bail out if the
7704    * allocation did not change
7705    */
7706   clutter_actor_update_constraints (self, &real_allocation);
7707
7708   /* adjust the allocation depending on the align/margin properties */
7709   clutter_actor_adjust_allocation (self, &real_allocation);
7710
7711   if (real_allocation.x2 < real_allocation.x1 ||
7712       real_allocation.y2 < real_allocation.y1)
7713     {
7714       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7715                  _clutter_actor_get_debug_name (self),
7716                  real_allocation.x2 - real_allocation.x1,
7717                  real_allocation.y2 - real_allocation.y1);
7718     }
7719
7720   /* we allow 0-sized actors, but not negative-sized ones */
7721   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7722   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7723
7724   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7725
7726   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7727                  real_allocation.y1 != old_allocation.y1);
7728
7729   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7730                   real_allocation.y2 != old_allocation.y2);
7731
7732   if (origin_changed || child_moved || size_changed)
7733     stage_allocation_changed = TRUE;
7734   else
7735     stage_allocation_changed = FALSE;
7736
7737   /* If we get an allocation "out of the blue"
7738    * (we did not queue relayout), then we want to
7739    * ignore it. But if we have needs_allocation set,
7740    * we want to guarantee that allocate() virtual
7741    * method is always called, i.e. that queue_relayout()
7742    * always results in an allocate() invocation on
7743    * an actor.
7744    *
7745    * The optimization here is to avoid re-allocating
7746    * actors that did not queue relayout and were
7747    * not moved.
7748    */
7749   if (!priv->needs_allocation && !stage_allocation_changed)
7750     {
7751       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7752       return;
7753     }
7754
7755   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7756    * clutter_actor_allocate(), it indicates whether the parent has its
7757    * absolute origin moved; when passed in to ClutterActor::allocate()
7758    * virtual method though, it indicates whether the child has its
7759    * absolute origin moved.  So we set it when child_moved is TRUE
7760    */
7761   if (child_moved)
7762     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7763
7764   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7765
7766   klass = CLUTTER_ACTOR_GET_CLASS (self);
7767   klass->allocate (self, &real_allocation, flags);
7768
7769   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7770
7771   if (stage_allocation_changed)
7772     clutter_actor_queue_redraw (self);
7773 }
7774
7775 /**
7776  * clutter_actor_set_allocation:
7777  * @self: a #ClutterActor
7778  * @box: a #ClutterActorBox
7779  * @flags: allocation flags
7780  *
7781  * Stores the allocation of @self as defined by @box.
7782  *
7783  * This function can only be called from within the implementation of
7784  * the #ClutterActorClass.allocate() virtual function.
7785  *
7786  * The allocation should have been adjusted to take into account constraints,
7787  * alignment, and margin properties. If you are implementing a #ClutterActor
7788  * subclass that provides its own layout management policy for its children
7789  * instead of using a #ClutterLayoutManager delegate, you should not call
7790  * this function on the children of @self; instead, you should call
7791  * clutter_actor_allocate(), which will adjust the allocation box for
7792  * you.
7793  *
7794  * This function should only be used by subclasses of #ClutterActor
7795  * that wish to store their allocation but cannot chain up to the
7796  * parent's implementation; the default implementation of the
7797  * #ClutterActorClass.allocate() virtual function will call this
7798  * function.
7799  *
7800  * It is important to note that, while chaining up was the recommended
7801  * behaviour for #ClutterActor subclasses prior to the introduction of
7802  * this function, it is recommended to call clutter_actor_set_allocation()
7803  * instead.
7804  *
7805  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7806  * to handle the allocation of its children, this function will call
7807  * the clutter_layout_manager_allocate() function only if the
7808  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7809  * expected that the subclass will call clutter_layout_manager_allocate()
7810  * by itself. For instance, the following code:
7811  *
7812  * |[
7813  * static void
7814  * my_actor_allocate (ClutterActor *actor,
7815  *                    const ClutterActorBox *allocation,
7816  *                    ClutterAllocationFlags flags)
7817  * {
7818  *   ClutterActorBox new_alloc;
7819  *   ClutterAllocationFlags new_flags;
7820  *
7821  *   adjust_allocation (allocation, &amp;new_alloc);
7822  *
7823  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7824  *
7825  *   /&ast; this will use the layout manager set on the actor &ast;/
7826  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7827  * }
7828  * ]|
7829  *
7830  * is equivalent to this:
7831  *
7832  * |[
7833  * static void
7834  * my_actor_allocate (ClutterActor *actor,
7835  *                    const ClutterActorBox *allocation,
7836  *                    ClutterAllocationFlags flags)
7837  * {
7838  *   ClutterLayoutManager *layout;
7839  *   ClutterActorBox new_alloc;
7840  *
7841  *   adjust_allocation (allocation, &amp;new_alloc);
7842  *
7843  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7844  *
7845  *   layout = clutter_actor_get_layout_manager (actor);
7846  *   clutter_layout_manager_allocate (layout,
7847  *                                    CLUTTER_CONTAINER (actor),
7848  *                                    &amp;new_alloc,
7849  *                                    flags);
7850  * }
7851  * ]|
7852  *
7853  * Since: 1.10
7854  */
7855 void
7856 clutter_actor_set_allocation (ClutterActor           *self,
7857                               const ClutterActorBox  *box,
7858                               ClutterAllocationFlags  flags)
7859 {
7860   ClutterActorPrivate *priv;
7861   gboolean changed;
7862
7863   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7864   g_return_if_fail (box != NULL);
7865
7866   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7867     {
7868       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7869                   "can only be called from within the implementation of "
7870                   "the ClutterActor::allocate() virtual function.");
7871       return;
7872     }
7873
7874   priv = self->priv;
7875
7876   g_object_freeze_notify (G_OBJECT (self));
7877
7878   changed = clutter_actor_set_allocation_internal (self, box, flags);
7879
7880   /* we allocate our children before we notify changes in our geometry,
7881    * so that people connecting to properties will be able to get valid
7882    * data out of the sub-tree of the scene graph that has this actor at
7883    * the root.
7884    */
7885   clutter_actor_maybe_layout_children (self, box, flags);
7886
7887   if (changed)
7888     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7889                    &priv->allocation,
7890                    priv->allocation_flags);
7891
7892   g_object_thaw_notify (G_OBJECT (self));
7893 }
7894
7895 /**
7896  * clutter_actor_set_geometry:
7897  * @self: A #ClutterActor
7898  * @geometry: A #ClutterGeometry
7899  *
7900  * Sets the actor's fixed position and forces its minimum and natural
7901  * size, in pixels. This means the untransformed actor will have the
7902  * given geometry. This is the same as calling clutter_actor_set_position()
7903  * and clutter_actor_set_size().
7904  *
7905  * Deprecated: 1.10: Use clutter_actor_set_position() and
7906  *   clutter_actor_set_size() instead.
7907  */
7908 void
7909 clutter_actor_set_geometry (ClutterActor          *self,
7910                             const ClutterGeometry *geometry)
7911 {
7912   g_object_freeze_notify (G_OBJECT (self));
7913
7914   clutter_actor_set_position (self, geometry->x, geometry->y);
7915   clutter_actor_set_size (self, geometry->width, geometry->height);
7916
7917   g_object_thaw_notify (G_OBJECT (self));
7918 }
7919
7920 /**
7921  * clutter_actor_get_geometry:
7922  * @self: A #ClutterActor
7923  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7924  *
7925  * Gets the size and position of an actor relative to its parent
7926  * actor. This is the same as calling clutter_actor_get_position() and
7927  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7928  * requested size and position if the actor's allocation is invalid.
7929  *
7930  * Deprecated: 1.10: Use clutter_actor_get_position() and
7931  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7932  *   instead.
7933  */
7934 void
7935 clutter_actor_get_geometry (ClutterActor    *self,
7936                             ClutterGeometry *geometry)
7937 {
7938   gfloat x, y, width, height;
7939
7940   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7941   g_return_if_fail (geometry != NULL);
7942
7943   clutter_actor_get_position (self, &x, &y);
7944   clutter_actor_get_size (self, &width, &height);
7945
7946   geometry->x = (int) x;
7947   geometry->y = (int) y;
7948   geometry->width = (int) width;
7949   geometry->height = (int) height;
7950 }
7951
7952 /**
7953  * clutter_actor_set_position
7954  * @self: A #ClutterActor
7955  * @x: New left position of actor in pixels.
7956  * @y: New top position of actor in pixels.
7957  *
7958  * Sets the actor's fixed position in pixels relative to any parent
7959  * actor.
7960  *
7961  * If a layout manager is in use, this position will override the
7962  * layout manager and force a fixed position.
7963  */
7964 void
7965 clutter_actor_set_position (ClutterActor *self,
7966                             gfloat        x,
7967                             gfloat        y)
7968 {
7969   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7970
7971   g_object_freeze_notify (G_OBJECT (self));
7972
7973   clutter_actor_set_x (self, x);
7974   clutter_actor_set_y (self, y);
7975
7976   g_object_thaw_notify (G_OBJECT (self));
7977 }
7978
7979 /**
7980  * clutter_actor_get_fixed_position_set:
7981  * @self: A #ClutterActor
7982  *
7983  * Checks whether an actor has a fixed position set (and will thus be
7984  * unaffected by any layout manager).
7985  *
7986  * Return value: %TRUE if the fixed position is set on the actor
7987  *
7988  * Since: 0.8
7989  */
7990 gboolean
7991 clutter_actor_get_fixed_position_set (ClutterActor *self)
7992 {
7993   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
7994
7995   return self->priv->position_set;
7996 }
7997
7998 /**
7999  * clutter_actor_set_fixed_position_set:
8000  * @self: A #ClutterActor
8001  * @is_set: whether to use fixed position
8002  *
8003  * Sets whether an actor has a fixed position set (and will thus be
8004  * unaffected by any layout manager).
8005  *
8006  * Since: 0.8
8007  */
8008 void
8009 clutter_actor_set_fixed_position_set (ClutterActor *self,
8010                                       gboolean      is_set)
8011 {
8012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8013
8014   if (self->priv->position_set == (is_set != FALSE))
8015     return;
8016
8017   self->priv->position_set = is_set != FALSE;
8018   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8019
8020   clutter_actor_queue_relayout (self);
8021 }
8022
8023 /**
8024  * clutter_actor_move_by:
8025  * @self: A #ClutterActor
8026  * @dx: Distance to move Actor on X axis.
8027  * @dy: Distance to move Actor on Y axis.
8028  *
8029  * Moves an actor by the specified distance relative to its current
8030  * position in pixels.
8031  *
8032  * This function modifies the fixed position of an actor and thus removes
8033  * it from any layout management. Another way to move an actor is with an
8034  * anchor point, see clutter_actor_set_anchor_point().
8035  *
8036  * Since: 0.2
8037  */
8038 void
8039 clutter_actor_move_by (ClutterActor *self,
8040                        gfloat        dx,
8041                        gfloat        dy)
8042 {
8043   const ClutterLayoutInfo *info;
8044   gfloat x, y;
8045
8046   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8047
8048   info = _clutter_actor_get_layout_info_or_defaults (self);
8049   x = info->fixed_x;
8050   y = info->fixed_y;
8051
8052   clutter_actor_set_position (self, x + dx, y + dy);
8053 }
8054
8055 static void
8056 clutter_actor_set_min_width (ClutterActor *self,
8057                              gfloat        min_width)
8058 {
8059   ClutterActorPrivate *priv = self->priv;
8060   ClutterActorBox old = { 0, };
8061   ClutterLayoutInfo *info;
8062
8063   /* if we are setting the size on a top-level actor and the
8064    * backend only supports static top-levels (e.g. framebuffers)
8065    * then we ignore the passed value and we override it with
8066    * the stage implementation's preferred size.
8067    */
8068   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8069       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8070     return;
8071
8072   info = _clutter_actor_get_layout_info (self);
8073
8074   if (priv->min_width_set && min_width == info->min_width)
8075     return;
8076
8077   g_object_freeze_notify (G_OBJECT (self));
8078
8079   clutter_actor_store_old_geometry (self, &old);
8080
8081   info->min_width = min_width;
8082   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8083   clutter_actor_set_min_width_set (self, TRUE);
8084
8085   clutter_actor_notify_if_geometry_changed (self, &old);
8086
8087   g_object_thaw_notify (G_OBJECT (self));
8088
8089   clutter_actor_queue_relayout (self);
8090 }
8091
8092 static void
8093 clutter_actor_set_min_height (ClutterActor *self,
8094                               gfloat        min_height)
8095
8096 {
8097   ClutterActorPrivate *priv = self->priv;
8098   ClutterActorBox old = { 0, };
8099   ClutterLayoutInfo *info;
8100
8101   /* if we are setting the size on a top-level actor and the
8102    * backend only supports static top-levels (e.g. framebuffers)
8103    * then we ignore the passed value and we override it with
8104    * the stage implementation's preferred size.
8105    */
8106   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8107       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8108     return;
8109
8110   info = _clutter_actor_get_layout_info (self);
8111
8112   if (priv->min_height_set && min_height == info->min_height)
8113     return;
8114
8115   g_object_freeze_notify (G_OBJECT (self));
8116
8117   clutter_actor_store_old_geometry (self, &old);
8118
8119   info->min_height = min_height;
8120   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8121   clutter_actor_set_min_height_set (self, TRUE);
8122
8123   clutter_actor_notify_if_geometry_changed (self, &old);
8124
8125   g_object_thaw_notify (G_OBJECT (self));
8126
8127   clutter_actor_queue_relayout (self);
8128 }
8129
8130 static void
8131 clutter_actor_set_natural_width (ClutterActor *self,
8132                                  gfloat        natural_width)
8133 {
8134   ClutterActorPrivate *priv = self->priv;
8135   ClutterActorBox old = { 0, };
8136   ClutterLayoutInfo *info;
8137
8138   /* if we are setting the size on a top-level actor and the
8139    * backend only supports static top-levels (e.g. framebuffers)
8140    * then we ignore the passed value and we override it with
8141    * the stage implementation's preferred size.
8142    */
8143   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8144       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8145     return;
8146
8147   info = _clutter_actor_get_layout_info (self);
8148
8149   if (priv->natural_width_set && natural_width == info->natural_width)
8150     return;
8151
8152   g_object_freeze_notify (G_OBJECT (self));
8153
8154   clutter_actor_store_old_geometry (self, &old);
8155
8156   info->natural_width = natural_width;
8157   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8158   clutter_actor_set_natural_width_set (self, TRUE);
8159
8160   clutter_actor_notify_if_geometry_changed (self, &old);
8161
8162   g_object_thaw_notify (G_OBJECT (self));
8163
8164   clutter_actor_queue_relayout (self);
8165 }
8166
8167 static void
8168 clutter_actor_set_natural_height (ClutterActor *self,
8169                                   gfloat        natural_height)
8170 {
8171   ClutterActorPrivate *priv = self->priv;
8172   ClutterActorBox old = { 0, };
8173   ClutterLayoutInfo *info;
8174
8175   /* if we are setting the size on a top-level actor and the
8176    * backend only supports static top-levels (e.g. framebuffers)
8177    * then we ignore the passed value and we override it with
8178    * the stage implementation's preferred size.
8179    */
8180   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8181       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8182     return;
8183
8184   info = _clutter_actor_get_layout_info (self);
8185
8186   if (priv->natural_height_set && natural_height == info->natural_height)
8187     return;
8188
8189   g_object_freeze_notify (G_OBJECT (self));
8190
8191   clutter_actor_store_old_geometry (self, &old);
8192
8193   info->natural_height = natural_height;
8194   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8195   clutter_actor_set_natural_height_set (self, TRUE);
8196
8197   clutter_actor_notify_if_geometry_changed (self, &old);
8198
8199   g_object_thaw_notify (G_OBJECT (self));
8200
8201   clutter_actor_queue_relayout (self);
8202 }
8203
8204 static void
8205 clutter_actor_set_min_width_set (ClutterActor *self,
8206                                  gboolean      use_min_width)
8207 {
8208   ClutterActorPrivate *priv = self->priv;
8209   ClutterActorBox old = { 0, };
8210
8211   if (priv->min_width_set == (use_min_width != FALSE))
8212     return;
8213
8214   clutter_actor_store_old_geometry (self, &old);
8215
8216   priv->min_width_set = use_min_width != FALSE;
8217   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8218
8219   clutter_actor_notify_if_geometry_changed (self, &old);
8220
8221   clutter_actor_queue_relayout (self);
8222 }
8223
8224 static void
8225 clutter_actor_set_min_height_set (ClutterActor *self,
8226                                   gboolean      use_min_height)
8227 {
8228   ClutterActorPrivate *priv = self->priv;
8229   ClutterActorBox old = { 0, };
8230
8231   if (priv->min_height_set == (use_min_height != FALSE))
8232     return;
8233
8234   clutter_actor_store_old_geometry (self, &old);
8235
8236   priv->min_height_set = use_min_height != FALSE;
8237   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8238
8239   clutter_actor_notify_if_geometry_changed (self, &old);
8240
8241   clutter_actor_queue_relayout (self);
8242 }
8243
8244 static void
8245 clutter_actor_set_natural_width_set (ClutterActor *self,
8246                                      gboolean      use_natural_width)
8247 {
8248   ClutterActorPrivate *priv = self->priv;
8249   ClutterActorBox old = { 0, };
8250
8251   if (priv->natural_width_set == (use_natural_width != FALSE))
8252     return;
8253
8254   clutter_actor_store_old_geometry (self, &old);
8255
8256   priv->natural_width_set = use_natural_width != FALSE;
8257   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8258
8259   clutter_actor_notify_if_geometry_changed (self, &old);
8260
8261   clutter_actor_queue_relayout (self);
8262 }
8263
8264 static void
8265 clutter_actor_set_natural_height_set (ClutterActor *self,
8266                                       gboolean      use_natural_height)
8267 {
8268   ClutterActorPrivate *priv = self->priv;
8269   ClutterActorBox old = { 0, };
8270
8271   if (priv->natural_height_set == (use_natural_height != FALSE))
8272     return;
8273
8274   clutter_actor_store_old_geometry (self, &old);
8275
8276   priv->natural_height_set = use_natural_height != FALSE;
8277   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8278
8279   clutter_actor_notify_if_geometry_changed (self, &old);
8280
8281   clutter_actor_queue_relayout (self);
8282 }
8283
8284 /**
8285  * clutter_actor_set_request_mode:
8286  * @self: a #ClutterActor
8287  * @mode: the request mode
8288  *
8289  * Sets the geometry request mode of @self.
8290  *
8291  * The @mode determines the order for invoking
8292  * clutter_actor_get_preferred_width() and
8293  * clutter_actor_get_preferred_height()
8294  *
8295  * Since: 1.2
8296  */
8297 void
8298 clutter_actor_set_request_mode (ClutterActor       *self,
8299                                 ClutterRequestMode  mode)
8300 {
8301   ClutterActorPrivate *priv;
8302
8303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8304
8305   priv = self->priv;
8306
8307   if (priv->request_mode == mode)
8308     return;
8309
8310   priv->request_mode = mode;
8311
8312   priv->needs_width_request = TRUE;
8313   priv->needs_height_request = TRUE;
8314
8315   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8316
8317   clutter_actor_queue_relayout (self);
8318 }
8319
8320 /**
8321  * clutter_actor_get_request_mode:
8322  * @self: a #ClutterActor
8323  *
8324  * Retrieves the geometry request mode of @self
8325  *
8326  * Return value: the request mode for the actor
8327  *
8328  * Since: 1.2
8329  */
8330 ClutterRequestMode
8331 clutter_actor_get_request_mode (ClutterActor *self)
8332 {
8333   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8334                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8335
8336   return self->priv->request_mode;
8337 }
8338
8339 /* variant of set_width() without checks and without notification
8340  * freeze+thaw, for internal usage only
8341  */
8342 static inline void
8343 clutter_actor_set_width_internal (ClutterActor *self,
8344                                   gfloat        width)
8345 {
8346   if (width >= 0)
8347     {
8348       /* the Stage will use the :min-width to control the minimum
8349        * width to be resized to, so we should not be setting it
8350        * along with the :natural-width
8351        */
8352       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8353         clutter_actor_set_min_width (self, width);
8354
8355       clutter_actor_set_natural_width (self, width);
8356     }
8357   else
8358     {
8359       /* we only unset the :natural-width for the Stage */
8360       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8361         clutter_actor_set_min_width_set (self, FALSE);
8362
8363       clutter_actor_set_natural_width_set (self, FALSE);
8364     }
8365 }
8366
8367 /* variant of set_height() without checks and without notification
8368  * freeze+thaw, for internal usage only
8369  */
8370 static inline void
8371 clutter_actor_set_height_internal (ClutterActor *self,
8372                                    gfloat        height)
8373 {
8374   if (height >= 0)
8375     {
8376       /* see the comment above in set_width_internal() */
8377       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8378         clutter_actor_set_min_height (self, height);
8379
8380       clutter_actor_set_natural_height (self, height);
8381     }
8382   else
8383     {
8384       /* see the comment above in set_width_internal() */
8385       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8386         clutter_actor_set_min_height_set (self, FALSE);
8387
8388       clutter_actor_set_natural_height_set (self, FALSE);
8389     }
8390 }
8391
8392 /**
8393  * clutter_actor_set_size
8394  * @self: A #ClutterActor
8395  * @width: New width of actor in pixels, or -1
8396  * @height: New height of actor in pixels, or -1
8397  *
8398  * Sets the actor's size request in pixels. This overrides any
8399  * "normal" size request the actor would have. For example
8400  * a text actor might normally request the size of the text;
8401  * this function would force a specific size instead.
8402  *
8403  * If @width and/or @height are -1 the actor will use its
8404  * "normal" size request instead of overriding it, i.e.
8405  * you can "unset" the size with -1.
8406  *
8407  * This function sets or unsets both the minimum and natural size.
8408  */
8409 void
8410 clutter_actor_set_size (ClutterActor *self,
8411                         gfloat        width,
8412                         gfloat        height)
8413 {
8414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8415
8416   g_object_freeze_notify (G_OBJECT (self));
8417
8418   clutter_actor_set_width_internal (self, width);
8419   clutter_actor_set_height_internal (self, height);
8420
8421   g_object_thaw_notify (G_OBJECT (self));
8422 }
8423
8424 /**
8425  * clutter_actor_get_size:
8426  * @self: A #ClutterActor
8427  * @width: (out) (allow-none): return location for the width, or %NULL.
8428  * @height: (out) (allow-none): return location for the height, or %NULL.
8429  *
8430  * This function tries to "do what you mean" and return
8431  * the size an actor will have. If the actor has a valid
8432  * allocation, the allocation will be returned; otherwise,
8433  * the actors natural size request will be returned.
8434  *
8435  * If you care whether you get the request vs. the allocation, you
8436  * should probably call a different function like
8437  * clutter_actor_get_allocation_box() or
8438  * clutter_actor_get_preferred_width().
8439  *
8440  * Since: 0.2
8441  */
8442 void
8443 clutter_actor_get_size (ClutterActor *self,
8444                         gfloat       *width,
8445                         gfloat       *height)
8446 {
8447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8448
8449   if (width)
8450     *width = clutter_actor_get_width (self);
8451
8452   if (height)
8453     *height = clutter_actor_get_height (self);
8454 }
8455
8456 /**
8457  * clutter_actor_get_position:
8458  * @self: a #ClutterActor
8459  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8460  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8461  *
8462  * This function tries to "do what you mean" and tell you where the
8463  * actor is, prior to any transformations. Retrieves the fixed
8464  * position of an actor in pixels, if one has been set; otherwise, if
8465  * the allocation is valid, returns the actor's allocated position;
8466  * otherwise, returns 0,0.
8467  *
8468  * The returned position is in pixels.
8469  *
8470  * Since: 0.6
8471  */
8472 void
8473 clutter_actor_get_position (ClutterActor *self,
8474                             gfloat       *x,
8475                             gfloat       *y)
8476 {
8477   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8478
8479   if (x)
8480     *x = clutter_actor_get_x (self);
8481
8482   if (y)
8483     *y = clutter_actor_get_y (self);
8484 }
8485
8486 /**
8487  * clutter_actor_get_transformed_position:
8488  * @self: A #ClutterActor
8489  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8490  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8491  *
8492  * Gets the absolute position of an actor, in pixels relative to the stage.
8493  *
8494  * Since: 0.8
8495  */
8496 void
8497 clutter_actor_get_transformed_position (ClutterActor *self,
8498                                         gfloat       *x,
8499                                         gfloat       *y)
8500 {
8501   ClutterVertex v1;
8502   ClutterVertex v2;
8503
8504   v1.x = v1.y = v1.z = 0;
8505   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8506
8507   if (x)
8508     *x = v2.x;
8509
8510   if (y)
8511     *y = v2.y;
8512 }
8513
8514 /**
8515  * clutter_actor_get_transformed_size:
8516  * @self: A #ClutterActor
8517  * @width: (out) (allow-none): return location for the width, or %NULL
8518  * @height: (out) (allow-none): return location for the height, or %NULL
8519  *
8520  * Gets the absolute size of an actor in pixels, taking into account the
8521  * scaling factors.
8522  *
8523  * If the actor has a valid allocation, the allocated size will be used.
8524  * If the actor has not a valid allocation then the preferred size will
8525  * be transformed and returned.
8526  *
8527  * If you want the transformed allocation, see
8528  * clutter_actor_get_abs_allocation_vertices() instead.
8529  *
8530  * <note>When the actor (or one of its ancestors) is rotated around the
8531  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8532  * as a generic quadrangle; in that case this function returns the size
8533  * of the smallest rectangle that encapsulates the entire quad. Please
8534  * note that in this case no assumptions can be made about the relative
8535  * position of this envelope to the absolute position of the actor, as
8536  * returned by clutter_actor_get_transformed_position(); if you need this
8537  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8538  * to get the coords of the actual quadrangle.</note>
8539  *
8540  * Since: 0.8
8541  */
8542 void
8543 clutter_actor_get_transformed_size (ClutterActor *self,
8544                                     gfloat       *width,
8545                                     gfloat       *height)
8546 {
8547   ClutterActorPrivate *priv;
8548   ClutterVertex v[4];
8549   gfloat x_min, x_max, y_min, y_max;
8550   gint i;
8551
8552   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8553
8554   priv = self->priv;
8555
8556   /* if the actor hasn't been allocated yet, get the preferred
8557    * size and transform that
8558    */
8559   if (priv->needs_allocation)
8560     {
8561       gfloat natural_width, natural_height;
8562       ClutterActorBox box;
8563
8564       /* Make a fake allocation to transform.
8565        *
8566        * NB: _clutter_actor_transform_and_project_box expects a box in
8567        * the actor's coordinate space... */
8568
8569       box.x1 = 0;
8570       box.y1 = 0;
8571
8572       natural_width = natural_height = 0;
8573       clutter_actor_get_preferred_size (self, NULL, NULL,
8574                                         &natural_width,
8575                                         &natural_height);
8576
8577       box.x2 = natural_width;
8578       box.y2 = natural_height;
8579
8580       _clutter_actor_transform_and_project_box (self, &box, v);
8581     }
8582   else
8583     clutter_actor_get_abs_allocation_vertices (self, v);
8584
8585   x_min = x_max = v[0].x;
8586   y_min = y_max = v[0].y;
8587
8588   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8589     {
8590       if (v[i].x < x_min)
8591         x_min = v[i].x;
8592
8593       if (v[i].x > x_max)
8594         x_max = v[i].x;
8595
8596       if (v[i].y < y_min)
8597         y_min = v[i].y;
8598
8599       if (v[i].y > y_max)
8600         y_max = v[i].y;
8601     }
8602
8603   if (width)
8604     *width  = x_max - x_min;
8605
8606   if (height)
8607     *height = y_max - y_min;
8608 }
8609
8610 /**
8611  * clutter_actor_get_width:
8612  * @self: A #ClutterActor
8613  *
8614  * Retrieves the width of a #ClutterActor.
8615  *
8616  * If the actor has a valid allocation, this function will return the
8617  * width of the allocated area given to the actor.
8618  *
8619  * If the actor does not have a valid allocation, this function will
8620  * return the actor's natural width, that is the preferred width of
8621  * the actor.
8622  *
8623  * If you care whether you get the preferred width or the width that
8624  * has been assigned to the actor, you should probably call a different
8625  * function like clutter_actor_get_allocation_box() to retrieve the
8626  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8627  * preferred width.
8628  *
8629  * If an actor has a fixed width, for instance a width that has been
8630  * assigned using clutter_actor_set_width(), the width returned will
8631  * be the same value.
8632  *
8633  * Return value: the width of the actor, in pixels
8634  */
8635 gfloat
8636 clutter_actor_get_width (ClutterActor *self)
8637 {
8638   ClutterActorPrivate *priv;
8639
8640   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8641
8642   priv = self->priv;
8643
8644   if (priv->needs_allocation)
8645     {
8646       gfloat natural_width = 0;
8647
8648       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8649         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8650       else
8651         {
8652           gfloat natural_height = 0;
8653
8654           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8655           clutter_actor_get_preferred_width (self, natural_height,
8656                                              NULL,
8657                                              &natural_width);
8658         }
8659
8660       return natural_width;
8661     }
8662   else
8663     return priv->allocation.x2 - priv->allocation.x1;
8664 }
8665
8666 /**
8667  * clutter_actor_get_height:
8668  * @self: A #ClutterActor
8669  *
8670  * Retrieves the height of a #ClutterActor.
8671  *
8672  * If the actor has a valid allocation, this function will return the
8673  * height of the allocated area given to the actor.
8674  *
8675  * If the actor does not have a valid allocation, this function will
8676  * return the actor's natural height, that is the preferred height of
8677  * the actor.
8678  *
8679  * If you care whether you get the preferred height or the height that
8680  * has been assigned to the actor, you should probably call a different
8681  * function like clutter_actor_get_allocation_box() to retrieve the
8682  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8683  * preferred height.
8684  *
8685  * If an actor has a fixed height, for instance a height that has been
8686  * assigned using clutter_actor_set_height(), the height returned will
8687  * be the same value.
8688  *
8689  * Return value: the height of the actor, in pixels
8690  */
8691 gfloat
8692 clutter_actor_get_height (ClutterActor *self)
8693 {
8694   ClutterActorPrivate *priv;
8695
8696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8697
8698   priv = self->priv;
8699
8700   if (priv->needs_allocation)
8701     {
8702       gfloat natural_height = 0;
8703
8704       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8705         {
8706           gfloat natural_width = 0;
8707
8708           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8709           clutter_actor_get_preferred_height (self, natural_width,
8710                                               NULL, &natural_height);
8711         }
8712       else
8713         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8714
8715       return natural_height;
8716     }
8717   else
8718     return priv->allocation.y2 - priv->allocation.y1;
8719 }
8720
8721 /**
8722  * clutter_actor_set_width
8723  * @self: A #ClutterActor
8724  * @width: Requested new width for the actor, in pixels, or -1
8725  *
8726  * Forces a width on an actor, causing the actor's preferred width
8727  * and height (if any) to be ignored.
8728  *
8729  * If @width is -1 the actor will use its preferred width request
8730  * instead of overriding it, i.e. you can "unset" the width with -1.
8731  *
8732  * This function sets both the minimum and natural size of the actor.
8733  *
8734  * since: 0.2
8735  */
8736 void
8737 clutter_actor_set_width (ClutterActor *self,
8738                          gfloat        width)
8739 {
8740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8741
8742   g_object_freeze_notify (G_OBJECT (self));
8743
8744   clutter_actor_set_width_internal (self, width);
8745
8746   g_object_thaw_notify (G_OBJECT (self));
8747 }
8748
8749 /**
8750  * clutter_actor_set_height
8751  * @self: A #ClutterActor
8752  * @height: Requested new height for the actor, in pixels, or -1
8753  *
8754  * Forces a height on an actor, causing the actor's preferred width
8755  * and height (if any) to be ignored.
8756  *
8757  * If @height is -1 the actor will use its preferred height instead of
8758  * overriding it, i.e. you can "unset" the height with -1.
8759  *
8760  * This function sets both the minimum and natural size of the actor.
8761  *
8762  * since: 0.2
8763  */
8764 void
8765 clutter_actor_set_height (ClutterActor *self,
8766                           gfloat        height)
8767 {
8768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8769
8770   g_object_freeze_notify (G_OBJECT (self));
8771
8772   clutter_actor_set_height_internal (self, height);
8773
8774   g_object_thaw_notify (G_OBJECT (self));
8775 }
8776
8777 /**
8778  * clutter_actor_set_x:
8779  * @self: a #ClutterActor
8780  * @x: the actor's position on the X axis
8781  *
8782  * Sets the actor's X coordinate, relative to its parent, in pixels.
8783  *
8784  * Overrides any layout manager and forces a fixed position for
8785  * the actor.
8786  *
8787  * Since: 0.6
8788  */
8789 void
8790 clutter_actor_set_x (ClutterActor *self,
8791                      gfloat        x)
8792 {
8793   ClutterActorBox old = { 0, };
8794   ClutterActorPrivate *priv;
8795   ClutterLayoutInfo *info;
8796
8797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8798
8799   priv = self->priv;
8800
8801   info = _clutter_actor_get_layout_info (self);
8802
8803   if (priv->position_set && info->fixed_x == x)
8804     return;
8805
8806   clutter_actor_store_old_geometry (self, &old);
8807
8808   info->fixed_x = x;
8809   clutter_actor_set_fixed_position_set (self, TRUE);
8810
8811   clutter_actor_notify_if_geometry_changed (self, &old);
8812
8813   clutter_actor_queue_relayout (self);
8814 }
8815
8816 /**
8817  * clutter_actor_set_y:
8818  * @self: a #ClutterActor
8819  * @y: the actor's position on the Y axis
8820  *
8821  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8822  *
8823  * Overrides any layout manager and forces a fixed position for
8824  * the actor.
8825  *
8826  * Since: 0.6
8827  */
8828 void
8829 clutter_actor_set_y (ClutterActor *self,
8830                      gfloat        y)
8831 {
8832   ClutterActorBox old = { 0, };
8833   ClutterActorPrivate *priv;
8834   ClutterLayoutInfo *info;
8835
8836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8837
8838   priv = self->priv;
8839
8840   info = _clutter_actor_get_layout_info (self);
8841
8842   if (priv->position_set && info->fixed_y == y)
8843     return;
8844
8845   clutter_actor_store_old_geometry (self, &old);
8846
8847   info->fixed_y = y;
8848   clutter_actor_set_fixed_position_set (self, TRUE);
8849
8850   clutter_actor_notify_if_geometry_changed (self, &old);
8851
8852   clutter_actor_queue_relayout (self);
8853 }
8854
8855 /**
8856  * clutter_actor_get_x
8857  * @self: A #ClutterActor
8858  *
8859  * Retrieves the X coordinate of a #ClutterActor.
8860  *
8861  * This function tries to "do what you mean", by returning the
8862  * correct value depending on the actor's state.
8863  *
8864  * If the actor has a valid allocation, this function will return
8865  * the X coordinate of the origin of the allocation box.
8866  *
8867  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8868  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8869  * function will return that coordinate.
8870  *
8871  * If both the allocation and a fixed position are missing, this function
8872  * will return 0.
8873  *
8874  * Return value: the X coordinate, in pixels, ignoring any
8875  *   transformation (i.e. scaling, rotation)
8876  */
8877 gfloat
8878 clutter_actor_get_x (ClutterActor *self)
8879 {
8880   ClutterActorPrivate *priv;
8881
8882   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8883
8884   priv = self->priv;
8885
8886   if (priv->needs_allocation)
8887     {
8888       if (priv->position_set)
8889         {
8890           const ClutterLayoutInfo *info;
8891
8892           info = _clutter_actor_get_layout_info_or_defaults (self);
8893
8894           return info->fixed_x;
8895         }
8896       else
8897         return 0;
8898     }
8899   else
8900     return priv->allocation.x1;
8901 }
8902
8903 /**
8904  * clutter_actor_get_y
8905  * @self: A #ClutterActor
8906  *
8907  * Retrieves the Y coordinate of a #ClutterActor.
8908  *
8909  * This function tries to "do what you mean", by returning the
8910  * correct value depending on the actor's state.
8911  *
8912  * If the actor has a valid allocation, this function will return
8913  * the Y coordinate of the origin of the allocation box.
8914  *
8915  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8916  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8917  * function will return that coordinate.
8918  *
8919  * If both the allocation and a fixed position are missing, this function
8920  * will return 0.
8921  *
8922  * Return value: the Y coordinate, in pixels, ignoring any
8923  *   transformation (i.e. scaling, rotation)
8924  */
8925 gfloat
8926 clutter_actor_get_y (ClutterActor *self)
8927 {
8928   ClutterActorPrivate *priv;
8929
8930   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8931
8932   priv = self->priv;
8933
8934   if (priv->needs_allocation)
8935     {
8936       if (priv->position_set)
8937         {
8938           const ClutterLayoutInfo *info;
8939
8940           info = _clutter_actor_get_layout_info_or_defaults (self);
8941
8942           return info->fixed_y;
8943         }
8944       else
8945         return 0;
8946     }
8947   else
8948     return priv->allocation.y1;
8949 }
8950
8951 /**
8952  * clutter_actor_set_scale:
8953  * @self: A #ClutterActor
8954  * @scale_x: double factor to scale actor by horizontally.
8955  * @scale_y: double factor to scale actor by vertically.
8956  *
8957  * Scales an actor with the given factors. The scaling is relative to
8958  * the scale center and the anchor point. The scale center is
8959  * unchanged by this function and defaults to 0,0.
8960  *
8961  * Since: 0.2
8962  */
8963 void
8964 clutter_actor_set_scale (ClutterActor *self,
8965                          gdouble       scale_x,
8966                          gdouble       scale_y)
8967 {
8968   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8969
8970   g_object_freeze_notify (G_OBJECT (self));
8971
8972   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8973   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8974
8975   g_object_thaw_notify (G_OBJECT (self));
8976 }
8977
8978 /**
8979  * clutter_actor_set_scale_full:
8980  * @self: A #ClutterActor
8981  * @scale_x: double factor to scale actor by horizontally.
8982  * @scale_y: double factor to scale actor by vertically.
8983  * @center_x: X coordinate of the center of the scale.
8984  * @center_y: Y coordinate of the center of the scale
8985  *
8986  * Scales an actor with the given factors around the given center
8987  * point. The center point is specified in pixels relative to the
8988  * anchor point (usually the top left corner of the actor).
8989  *
8990  * Since: 1.0
8991  */
8992 void
8993 clutter_actor_set_scale_full (ClutterActor *self,
8994                               gdouble       scale_x,
8995                               gdouble       scale_y,
8996                               gfloat        center_x,
8997                               gfloat        center_y)
8998 {
8999   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9000
9001   g_object_freeze_notify (G_OBJECT (self));
9002
9003   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9004   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9005   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9006   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9007
9008   g_object_thaw_notify (G_OBJECT (self));
9009 }
9010
9011 /**
9012  * clutter_actor_set_scale_with_gravity:
9013  * @self: A #ClutterActor
9014  * @scale_x: double factor to scale actor by horizontally.
9015  * @scale_y: double factor to scale actor by vertically.
9016  * @gravity: the location of the scale center expressed as a compass
9017  * direction.
9018  *
9019  * Scales an actor with the given factors around the given
9020  * center point. The center point is specified as one of the compass
9021  * directions in #ClutterGravity. For example, setting it to north
9022  * will cause the top of the actor to remain unchanged and the rest of
9023  * the actor to expand left, right and downwards.
9024  *
9025  * Since: 1.0
9026  */
9027 void
9028 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9029                                       gdouble         scale_x,
9030                                       gdouble         scale_y,
9031                                       ClutterGravity  gravity)
9032 {
9033   ClutterTransformInfo *info;
9034   GObject *obj;
9035
9036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9037
9038   obj = G_OBJECT (self);
9039
9040   g_object_freeze_notify (obj);
9041
9042   info = _clutter_actor_get_transform_info (self);
9043   info->scale_x = scale_x;
9044   info->scale_y = scale_y;
9045
9046   if (gravity == CLUTTER_GRAVITY_NONE)
9047     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9048   else
9049     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9050
9051   self->priv->transform_valid = FALSE;
9052
9053   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9054   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9055   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9056   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9057   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9058
9059   clutter_actor_queue_redraw (self);
9060
9061   g_object_thaw_notify (obj);
9062 }
9063
9064 /**
9065  * clutter_actor_get_scale:
9066  * @self: A #ClutterActor
9067  * @scale_x: (out) (allow-none): Location to store horizonal
9068  *   scale factor, or %NULL.
9069  * @scale_y: (out) (allow-none): Location to store vertical
9070  *   scale factor, or %NULL.
9071  *
9072  * Retrieves an actors scale factors.
9073  *
9074  * Since: 0.2
9075  */
9076 void
9077 clutter_actor_get_scale (ClutterActor *self,
9078                          gdouble      *scale_x,
9079                          gdouble      *scale_y)
9080 {
9081   const ClutterTransformInfo *info;
9082
9083   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9084
9085   info = _clutter_actor_get_transform_info_or_defaults (self);
9086
9087   if (scale_x)
9088     *scale_x = info->scale_x;
9089
9090   if (scale_y)
9091     *scale_y = info->scale_y;
9092 }
9093
9094 /**
9095  * clutter_actor_get_scale_center:
9096  * @self: A #ClutterActor
9097  * @center_x: (out) (allow-none): Location to store the X position
9098  *   of the scale center, or %NULL.
9099  * @center_y: (out) (allow-none): Location to store the Y position
9100  *   of the scale center, or %NULL.
9101  *
9102  * Retrieves the scale center coordinate in pixels relative to the top
9103  * left corner of the actor. If the scale center was specified using a
9104  * #ClutterGravity this will calculate the pixel offset using the
9105  * current size of the actor.
9106  *
9107  * Since: 1.0
9108  */
9109 void
9110 clutter_actor_get_scale_center (ClutterActor *self,
9111                                 gfloat       *center_x,
9112                                 gfloat       *center_y)
9113 {
9114   const ClutterTransformInfo *info;
9115
9116   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9117
9118   info = _clutter_actor_get_transform_info_or_defaults (self);
9119
9120   clutter_anchor_coord_get_units (self, &info->scale_center,
9121                                   center_x,
9122                                   center_y,
9123                                   NULL);
9124 }
9125
9126 /**
9127  * clutter_actor_get_scale_gravity:
9128  * @self: A #ClutterActor
9129  *
9130  * Retrieves the scale center as a compass direction. If the scale
9131  * center was specified in pixels or units this will return
9132  * %CLUTTER_GRAVITY_NONE.
9133  *
9134  * Return value: the scale gravity
9135  *
9136  * Since: 1.0
9137  */
9138 ClutterGravity
9139 clutter_actor_get_scale_gravity (ClutterActor *self)
9140 {
9141   const ClutterTransformInfo *info;
9142
9143   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9144
9145   info = _clutter_actor_get_transform_info_or_defaults (self);
9146
9147   return clutter_anchor_coord_get_gravity (&info->scale_center);
9148 }
9149
9150 /**
9151  * clutter_actor_set_opacity:
9152  * @self: A #ClutterActor
9153  * @opacity: New opacity value for the actor.
9154  *
9155  * Sets the actor's opacity, with zero being completely transparent and
9156  * 255 (0xff) being fully opaque.
9157  */
9158 void
9159 clutter_actor_set_opacity (ClutterActor *self,
9160                            guint8        opacity)
9161 {
9162   ClutterActorPrivate *priv;
9163
9164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9165
9166   priv = self->priv;
9167
9168   if (priv->opacity != opacity)
9169     {
9170       priv->opacity = opacity;
9171
9172       /* Queue a redraw from the flatten effect so that it can use
9173          its cached image if available instead of having to redraw the
9174          actual actor. If it doesn't end up using the FBO then the
9175          effect is still able to continue the paint anyway. If there
9176          is no flatten effect yet then this is equivalent to queueing
9177          a full redraw */
9178       _clutter_actor_queue_redraw_full (self,
9179                                         0, /* flags */
9180                                         NULL, /* clip */
9181                                         priv->flatten_effect);
9182
9183       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9184     }
9185 }
9186
9187 /*
9188  * clutter_actor_get_paint_opacity_internal:
9189  * @self: a #ClutterActor
9190  *
9191  * Retrieves the absolute opacity of the actor, as it appears on the stage
9192  *
9193  * This function does not do type checks
9194  *
9195  * Return value: the absolute opacity of the actor
9196  */
9197 static guint8
9198 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9199 {
9200   ClutterActorPrivate *priv = self->priv;
9201   ClutterActor *parent;
9202
9203   /* override the top-level opacity to always be 255; even in
9204    * case of ClutterStage:use-alpha being TRUE we want the rest
9205    * of the scene to be painted
9206    */
9207   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9208     return 255;
9209
9210   if (priv->opacity_override >= 0)
9211     return priv->opacity_override;
9212
9213   parent = priv->parent;
9214
9215   /* Factor in the actual actors opacity with parents */
9216   if (parent != NULL)
9217     {
9218       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9219
9220       if (opacity != 0xff)
9221         return (opacity * priv->opacity) / 0xff;
9222     }
9223
9224   return priv->opacity;
9225
9226 }
9227
9228 /**
9229  * clutter_actor_get_paint_opacity:
9230  * @self: A #ClutterActor
9231  *
9232  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9233  *
9234  * This function traverses the hierarchy chain and composites the opacity of
9235  * the actor with that of its parents.
9236  *
9237  * This function is intended for subclasses to use in the paint virtual
9238  * function, to paint themselves with the correct opacity.
9239  *
9240  * Return value: The actor opacity value.
9241  *
9242  * Since: 0.8
9243  */
9244 guint8
9245 clutter_actor_get_paint_opacity (ClutterActor *self)
9246 {
9247   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9248
9249   return clutter_actor_get_paint_opacity_internal (self);
9250 }
9251
9252 /**
9253  * clutter_actor_get_opacity:
9254  * @self: a #ClutterActor
9255  *
9256  * Retrieves the opacity value of an actor, as set by
9257  * clutter_actor_set_opacity().
9258  *
9259  * For retrieving the absolute opacity of the actor inside a paint
9260  * virtual function, see clutter_actor_get_paint_opacity().
9261  *
9262  * Return value: the opacity of the actor
9263  */
9264 guint8
9265 clutter_actor_get_opacity (ClutterActor *self)
9266 {
9267   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9268
9269   return self->priv->opacity;
9270 }
9271
9272 /**
9273  * clutter_actor_set_offscreen_redirect:
9274  * @self: A #ClutterActor
9275  * @redirect: New offscreen redirect flags for the actor.
9276  *
9277  * Defines the circumstances where the actor should be redirected into
9278  * an offscreen image. The offscreen image is used to flatten the
9279  * actor into a single image while painting for two main reasons.
9280  * Firstly, when the actor is painted a second time without any of its
9281  * contents changing it can simply repaint the cached image without
9282  * descending further down the actor hierarchy. Secondly, it will make
9283  * the opacity look correct even if there are overlapping primitives
9284  * in the actor.
9285  *
9286  * Caching the actor could in some cases be a performance win and in
9287  * some cases be a performance lose so it is important to determine
9288  * which value is right for an actor before modifying this value. For
9289  * example, there is never any reason to flatten an actor that is just
9290  * a single texture (such as a #ClutterTexture) because it is
9291  * effectively already cached in an image so the offscreen would be
9292  * redundant. Also if the actor contains primitives that are far apart
9293  * with a large transparent area in the middle (such as a large
9294  * CluterGroup with a small actor in the top left and a small actor in
9295  * the bottom right) then the cached image will contain the entire
9296  * image of the large area and the paint will waste time blending all
9297  * of the transparent pixels in the middle.
9298  *
9299  * The default method of implementing opacity on a container simply
9300  * forwards on the opacity to all of the children. If the children are
9301  * overlapping then it will appear as if they are two separate glassy
9302  * objects and there will be a break in the color where they
9303  * overlap. By redirecting to an offscreen buffer it will be as if the
9304  * two opaque objects are combined into one and then made transparent
9305  * which is usually what is expected.
9306  *
9307  * The image below demonstrates the difference between redirecting and
9308  * not. The image shows two Clutter groups, each containing a red and
9309  * a green rectangle which overlap. The opacity on the group is set to
9310  * 128 (which is 50%). When the offscreen redirect is not used, the
9311  * red rectangle can be seen through the blue rectangle as if the two
9312  * rectangles were separately transparent. When the redirect is used
9313  * the group as a whole is transparent instead so the red rectangle is
9314  * not visible where they overlap.
9315  *
9316  * <figure id="offscreen-redirect">
9317  *   <title>Sample of using an offscreen redirect for transparency</title>
9318  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9319  * </figure>
9320  *
9321  * The default value for this property is 0, so we effectively will
9322  * never redirect an actor offscreen by default. This means that there
9323  * are times that transparent actors may look glassy as described
9324  * above. The reason this is the default is because there is a
9325  * performance trade off between quality and performance here. In many
9326  * cases the default form of glassy opacity looks good enough, but if
9327  * it's not you will need to set the
9328  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9329  * redirection for opacity.
9330  *
9331  * Custom actors that don't contain any overlapping primitives are
9332  * recommended to override the has_overlaps() virtual to return %FALSE
9333  * for maximum efficiency.
9334  *
9335  * Since: 1.8
9336  */
9337 void
9338 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9339                                       ClutterOffscreenRedirect redirect)
9340 {
9341   ClutterActorPrivate *priv;
9342
9343   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9344
9345   priv = self->priv;
9346
9347   if (priv->offscreen_redirect != redirect)
9348     {
9349       priv->offscreen_redirect = redirect;
9350
9351       /* Queue a redraw from the effect so that it can use its cached
9352          image if available instead of having to redraw the actual
9353          actor. If it doesn't end up using the FBO then the effect is
9354          still able to continue the paint anyway. If there is no
9355          effect then this is equivalent to queuing a full redraw */
9356       _clutter_actor_queue_redraw_full (self,
9357                                         0, /* flags */
9358                                         NULL, /* clip */
9359                                         priv->flatten_effect);
9360
9361       g_object_notify_by_pspec (G_OBJECT (self),
9362                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9363     }
9364 }
9365
9366 /**
9367  * clutter_actor_get_offscreen_redirect:
9368  * @self: a #ClutterActor
9369  *
9370  * Retrieves whether to redirect the actor to an offscreen buffer, as
9371  * set by clutter_actor_set_offscreen_redirect().
9372  *
9373  * Return value: the value of the offscreen-redirect property of the actor
9374  *
9375  * Since: 1.8
9376  */
9377 ClutterOffscreenRedirect
9378 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9379 {
9380   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9381
9382   return self->priv->offscreen_redirect;
9383 }
9384
9385 /**
9386  * clutter_actor_set_name:
9387  * @self: A #ClutterActor
9388  * @name: Textual tag to apply to actor
9389  *
9390  * Sets the given name to @self. The name can be used to identify
9391  * a #ClutterActor.
9392  */
9393 void
9394 clutter_actor_set_name (ClutterActor *self,
9395                         const gchar  *name)
9396 {
9397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9398
9399   g_free (self->priv->name);
9400   self->priv->name = g_strdup (name);
9401
9402   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9403 }
9404
9405 /**
9406  * clutter_actor_get_name:
9407  * @self: A #ClutterActor
9408  *
9409  * Retrieves the name of @self.
9410  *
9411  * Return value: the name of the actor, or %NULL. The returned string is
9412  *   owned by the actor and should not be modified or freed.
9413  */
9414 const gchar *
9415 clutter_actor_get_name (ClutterActor *self)
9416 {
9417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9418
9419   return self->priv->name;
9420 }
9421
9422 /**
9423  * clutter_actor_get_gid:
9424  * @self: A #ClutterActor
9425  *
9426  * Retrieves the unique id for @self.
9427  *
9428  * Return value: Globally unique value for this object instance.
9429  *
9430  * Since: 0.6
9431  *
9432  * Deprecated: 1.8: The id is not used any longer.
9433  */
9434 guint32
9435 clutter_actor_get_gid (ClutterActor *self)
9436 {
9437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9438
9439   return self->priv->id;
9440 }
9441
9442 /**
9443  * clutter_actor_set_depth:
9444  * @self: a #ClutterActor
9445  * @depth: Z co-ord
9446  *
9447  * Sets the Z coordinate of @self to @depth.
9448  *
9449  * The unit used by @depth is dependant on the perspective setup. See
9450  * also clutter_stage_set_perspective().
9451  */
9452 void
9453 clutter_actor_set_depth (ClutterActor *self,
9454                          gfloat        depth)
9455 {
9456   ClutterActorPrivate *priv;
9457
9458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9459
9460   priv = self->priv;
9461
9462   if (priv->z != depth)
9463     {
9464       /* Sets Z value - XXX 2.0: should we invert? */
9465       priv->z = depth;
9466
9467       priv->transform_valid = FALSE;
9468
9469       /* FIXME - remove this crap; sadly, there are still containers
9470        * in Clutter that depend on this utter brain damage
9471        */
9472       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9473
9474       clutter_actor_queue_redraw (self);
9475
9476       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9477     }
9478 }
9479
9480 /**
9481  * clutter_actor_get_depth:
9482  * @self: a #ClutterActor
9483  *
9484  * Retrieves the depth of @self.
9485  *
9486  * Return value: the depth of the actor
9487  */
9488 gfloat
9489 clutter_actor_get_depth (ClutterActor *self)
9490 {
9491   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9492
9493   return self->priv->z;
9494 }
9495
9496 /**
9497  * clutter_actor_set_rotation:
9498  * @self: a #ClutterActor
9499  * @axis: the axis of rotation
9500  * @angle: the angle of rotation
9501  * @x: X coordinate of the rotation center
9502  * @y: Y coordinate of the rotation center
9503  * @z: Z coordinate of the rotation center
9504  *
9505  * Sets the rotation angle of @self around the given axis.
9506  *
9507  * The rotation center coordinates used depend on the value of @axis:
9508  * <itemizedlist>
9509  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9510  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9511  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9512  * </itemizedlist>
9513  *
9514  * The rotation coordinates are relative to the anchor point of the
9515  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9516  * point is set, the upper left corner is assumed as the origin.
9517  *
9518  * Since: 0.8
9519  */
9520 void
9521 clutter_actor_set_rotation (ClutterActor      *self,
9522                             ClutterRotateAxis  axis,
9523                             gdouble            angle,
9524                             gfloat             x,
9525                             gfloat             y,
9526                             gfloat             z)
9527 {
9528   ClutterVertex v;
9529
9530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9531
9532   v.x = x;
9533   v.y = y;
9534   v.z = z;
9535
9536   g_object_freeze_notify (G_OBJECT (self));
9537
9538   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9539   clutter_actor_set_rotation_center_internal (self, axis, &v);
9540
9541   g_object_thaw_notify (G_OBJECT (self));
9542 }
9543
9544 /**
9545  * clutter_actor_set_z_rotation_from_gravity:
9546  * @self: a #ClutterActor
9547  * @angle: the angle of rotation
9548  * @gravity: the center point of the rotation
9549  *
9550  * Sets the rotation angle of @self around the Z axis using the center
9551  * point specified as a compass point. For example to rotate such that
9552  * the center of the actor remains static you can use
9553  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9554  * will move accordingly.
9555  *
9556  * Since: 1.0
9557  */
9558 void
9559 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9560                                            gdouble         angle,
9561                                            ClutterGravity  gravity)
9562 {
9563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9564
9565   if (gravity == CLUTTER_GRAVITY_NONE)
9566     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9567   else
9568     {
9569       GObject *obj = G_OBJECT (self);
9570       ClutterTransformInfo *info;
9571
9572       info = _clutter_actor_get_transform_info (self);
9573
9574       g_object_freeze_notify (obj);
9575
9576       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9577
9578       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9579       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9580       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9581
9582       g_object_thaw_notify (obj);
9583     }
9584 }
9585
9586 /**
9587  * clutter_actor_get_rotation:
9588  * @self: a #ClutterActor
9589  * @axis: the axis of rotation
9590  * @x: (out): return value for the X coordinate of the center of rotation
9591  * @y: (out): return value for the Y coordinate of the center of rotation
9592  * @z: (out): return value for the Z coordinate of the center of rotation
9593  *
9594  * Retrieves the angle and center of rotation on the given axis,
9595  * set using clutter_actor_set_rotation().
9596  *
9597  * Return value: the angle of rotation
9598  *
9599  * Since: 0.8
9600  */
9601 gdouble
9602 clutter_actor_get_rotation (ClutterActor      *self,
9603                             ClutterRotateAxis  axis,
9604                             gfloat            *x,
9605                             gfloat            *y,
9606                             gfloat            *z)
9607 {
9608   const ClutterTransformInfo *info;
9609   const AnchorCoord *anchor_coord;
9610   gdouble retval = 0;
9611
9612   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9613
9614   info = _clutter_actor_get_transform_info_or_defaults (self);
9615
9616   switch (axis)
9617     {
9618     case CLUTTER_X_AXIS:
9619       anchor_coord = &info->rx_center;
9620       retval = info->rx_angle;
9621       break;
9622
9623     case CLUTTER_Y_AXIS:
9624       anchor_coord = &info->ry_center;
9625       retval = info->ry_angle;
9626       break;
9627
9628     case CLUTTER_Z_AXIS:
9629       anchor_coord = &info->rz_center;
9630       retval = info->rz_angle;
9631       break;
9632
9633     default:
9634       anchor_coord = NULL;
9635       retval = 0.0;
9636       break;
9637     }
9638
9639   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9640
9641   return retval;
9642 }
9643
9644 /**
9645  * clutter_actor_get_z_rotation_gravity:
9646  * @self: A #ClutterActor
9647  *
9648  * Retrieves the center for the rotation around the Z axis as a
9649  * compass direction. If the center was specified in pixels or units
9650  * this will return %CLUTTER_GRAVITY_NONE.
9651  *
9652  * Return value: the Z rotation center
9653  *
9654  * Since: 1.0
9655  */
9656 ClutterGravity
9657 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9658 {
9659   const ClutterTransformInfo *info;
9660
9661   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9662
9663   info = _clutter_actor_get_transform_info_or_defaults (self);
9664
9665   return clutter_anchor_coord_get_gravity (&info->rz_center);
9666 }
9667
9668 /**
9669  * clutter_actor_set_clip:
9670  * @self: A #ClutterActor
9671  * @xoff: X offset of the clip rectangle
9672  * @yoff: Y offset of the clip rectangle
9673  * @width: Width of the clip rectangle
9674  * @height: Height of the clip rectangle
9675  *
9676  * Sets clip area for @self. The clip area is always computed from the
9677  * upper left corner of the actor, even if the anchor point is set
9678  * otherwise.
9679  *
9680  * Since: 0.6
9681  */
9682 void
9683 clutter_actor_set_clip (ClutterActor *self,
9684                         gfloat        xoff,
9685                         gfloat        yoff,
9686                         gfloat        width,
9687                         gfloat        height)
9688 {
9689   ClutterActorPrivate *priv;
9690
9691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9692
9693   priv = self->priv;
9694
9695   if (priv->has_clip &&
9696       priv->clip.x == xoff &&
9697       priv->clip.y == yoff &&
9698       priv->clip.width == width &&
9699       priv->clip.height == height)
9700     return;
9701
9702   priv->clip.x = xoff;
9703   priv->clip.y = yoff;
9704   priv->clip.width = width;
9705   priv->clip.height = height;
9706
9707   priv->has_clip = TRUE;
9708
9709   clutter_actor_queue_redraw (self);
9710
9711   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9712   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9713 }
9714
9715 /**
9716  * clutter_actor_remove_clip
9717  * @self: A #ClutterActor
9718  *
9719  * Removes clip area from @self.
9720  */
9721 void
9722 clutter_actor_remove_clip (ClutterActor *self)
9723 {
9724   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9725
9726   if (!self->priv->has_clip)
9727     return;
9728
9729   self->priv->has_clip = FALSE;
9730
9731   clutter_actor_queue_redraw (self);
9732
9733   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9734 }
9735
9736 /**
9737  * clutter_actor_has_clip:
9738  * @self: a #ClutterActor
9739  *
9740  * Determines whether the actor has a clip area set or not.
9741  *
9742  * Return value: %TRUE if the actor has a clip area set.
9743  *
9744  * Since: 0.1.1
9745  */
9746 gboolean
9747 clutter_actor_has_clip (ClutterActor *self)
9748 {
9749   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9750
9751   return self->priv->has_clip;
9752 }
9753
9754 /**
9755  * clutter_actor_get_clip:
9756  * @self: a #ClutterActor
9757  * @xoff: (out) (allow-none): return location for the X offset of
9758  *   the clip rectangle, or %NULL
9759  * @yoff: (out) (allow-none): return location for the Y offset of
9760  *   the clip rectangle, or %NULL
9761  * @width: (out) (allow-none): return location for the width of
9762  *   the clip rectangle, or %NULL
9763  * @height: (out) (allow-none): return location for the height of
9764  *   the clip rectangle, or %NULL
9765  *
9766  * Gets the clip area for @self, if any is set
9767  *
9768  * Since: 0.6
9769  */
9770 void
9771 clutter_actor_get_clip (ClutterActor *self,
9772                         gfloat       *xoff,
9773                         gfloat       *yoff,
9774                         gfloat       *width,
9775                         gfloat       *height)
9776 {
9777   ClutterActorPrivate *priv;
9778
9779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9780
9781   priv = self->priv;
9782
9783   if (!priv->has_clip)
9784     return;
9785
9786   if (xoff != NULL)
9787     *xoff = priv->clip.x;
9788
9789   if (yoff != NULL)
9790     *yoff = priv->clip.y;
9791
9792   if (width != NULL)
9793     *width = priv->clip.width;
9794
9795   if (height != NULL)
9796     *height = priv->clip.height;
9797 }
9798
9799 /**
9800  * clutter_actor_get_children:
9801  * @self: a #ClutterActor
9802  *
9803  * Retrieves the list of children of @self.
9804  *
9805  * Return value: (transfer container) (element-type ClutterActor): A newly
9806  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9807  *   done.
9808  *
9809  * Since: 1.10
9810  */
9811 GList *
9812 clutter_actor_get_children (ClutterActor *self)
9813 {
9814   ClutterActor *iter;
9815   GList *res;
9816
9817   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9818
9819   /* we walk the list backward so that we can use prepend(),
9820    * which is O(1)
9821    */
9822   for (iter = self->priv->last_child, res = NULL;
9823        iter != NULL;
9824        iter = iter->priv->prev_sibling)
9825     {
9826       res = g_list_prepend (res, iter);
9827     }
9828
9829   return res;
9830 }
9831
9832 /*< private >
9833  * insert_child_at_depth:
9834  * @self: a #ClutterActor
9835  * @child: a #ClutterActor
9836  *
9837  * Inserts @child inside the list of children held by @self, using
9838  * the depth as the insertion criteria.
9839  *
9840  * This sadly makes the insertion not O(1), but we can keep the
9841  * list sorted so that the painters algorithm we use for painting
9842  * the children will work correctly.
9843  */
9844 static void
9845 insert_child_at_depth (ClutterActor *self,
9846                        ClutterActor *child,
9847                        gpointer      dummy G_GNUC_UNUSED)
9848 {
9849   ClutterActor *iter;
9850
9851   child->priv->parent = self;
9852
9853   /* special-case the first child */
9854   if (self->priv->n_children == 0)
9855     {
9856       self->priv->first_child = child;
9857       self->priv->last_child = child;
9858
9859       child->priv->next_sibling = NULL;
9860       child->priv->prev_sibling = NULL;
9861
9862       return;
9863     }
9864
9865   /* Find the right place to insert the child so that it will still be
9866      sorted and the child will be after all of the actors at the same
9867      dept */
9868   for (iter = self->priv->first_child;
9869        iter != NULL;
9870        iter = iter->priv->next_sibling)
9871     {
9872       if (iter->priv->z > child->priv->z)
9873         break;
9874     }
9875
9876   if (iter != NULL)
9877     {
9878       ClutterActor *tmp = iter->priv->prev_sibling;
9879
9880       if (tmp != NULL)
9881         tmp->priv->next_sibling = child;
9882
9883       /* Insert the node before the found one */
9884       child->priv->prev_sibling = iter->priv->prev_sibling;
9885       child->priv->next_sibling = iter;
9886       iter->priv->prev_sibling = child;
9887     }
9888   else
9889     {
9890       ClutterActor *tmp = self->priv->last_child;
9891
9892       if (tmp != NULL)
9893         tmp->priv->next_sibling = child;
9894
9895       /* insert the node at the end of the list */
9896       child->priv->prev_sibling = self->priv->last_child;
9897       child->priv->next_sibling = NULL;
9898     }
9899
9900   if (child->priv->prev_sibling == NULL)
9901     self->priv->first_child = child;
9902
9903   if (child->priv->next_sibling == NULL)
9904     self->priv->last_child = child;
9905 }
9906
9907 static void
9908 insert_child_at_index (ClutterActor *self,
9909                        ClutterActor *child,
9910                        gpointer      data_)
9911 {
9912   gint index_ = GPOINTER_TO_INT (data_);
9913
9914   child->priv->parent = self;
9915
9916   if (index_ == 0)
9917     {
9918       ClutterActor *tmp = self->priv->first_child;
9919
9920       if (tmp != NULL)
9921         tmp->priv->prev_sibling = child;
9922
9923       child->priv->prev_sibling = NULL;
9924       child->priv->next_sibling = tmp;
9925     }
9926   else if (index_ < 0)
9927     {
9928       ClutterActor *tmp = self->priv->last_child;
9929
9930       if (tmp != NULL)
9931         tmp->priv->next_sibling = child;
9932
9933       child->priv->prev_sibling = tmp;
9934       child->priv->next_sibling = NULL;
9935     }
9936   else
9937     {
9938       ClutterActor *iter;
9939       int i;
9940
9941       for (iter = self->priv->first_child, i = 0;
9942            iter != NULL;
9943            iter = iter->priv->next_sibling, i += 1)
9944         {
9945           if (index_ == i)
9946             {
9947               ClutterActor *tmp = iter->priv->prev_sibling;
9948
9949               child->priv->prev_sibling = tmp;
9950               child->priv->next_sibling = iter;
9951
9952               iter->priv->prev_sibling = child;
9953
9954               if (tmp != NULL)
9955                 tmp->priv->next_sibling = child;
9956
9957               break;
9958             }
9959         }
9960     }
9961
9962   if (child->priv->prev_sibling == NULL)
9963     self->priv->first_child = child;
9964
9965   if (child->priv->next_sibling == NULL)
9966     self->priv->last_child = child;
9967 }
9968
9969 static void
9970 insert_child_above (ClutterActor *self,
9971                     ClutterActor *child,
9972                     gpointer      data)
9973 {
9974   ClutterActor *sibling = data;
9975
9976   child->priv->parent = self;
9977
9978   if (sibling == NULL)
9979     sibling = self->priv->last_child;
9980
9981   child->priv->prev_sibling = sibling;
9982
9983   if (sibling != NULL)
9984     {
9985       ClutterActor *tmp = sibling->priv->next_sibling;
9986
9987       child->priv->next_sibling = tmp;
9988
9989       if (tmp != NULL)
9990         tmp->priv->prev_sibling = child;
9991
9992       sibling->priv->next_sibling = child;
9993     }
9994   else
9995     child->priv->next_sibling = NULL;
9996
9997   if (child->priv->prev_sibling == NULL)
9998     self->priv->first_child = child;
9999
10000   if (child->priv->next_sibling == NULL)
10001     self->priv->last_child = child;
10002 }
10003
10004 static void
10005 insert_child_below (ClutterActor *self,
10006                     ClutterActor *child,
10007                     gpointer      data)
10008 {
10009   ClutterActor *sibling = data;
10010
10011   child->priv->parent = self;
10012
10013   if (sibling == NULL)
10014     sibling = self->priv->first_child;
10015
10016   child->priv->next_sibling = sibling;
10017
10018   if (sibling != NULL)
10019     {
10020       ClutterActor *tmp = sibling->priv->prev_sibling;
10021
10022       child->priv->prev_sibling = tmp;
10023
10024       if (tmp != NULL)
10025         tmp->priv->next_sibling = child;
10026
10027       sibling->priv->prev_sibling = child;
10028     }
10029   else
10030     child->priv->prev_sibling = NULL;
10031
10032   if (child->priv->prev_sibling == NULL)
10033     self->priv->first_child = child;
10034
10035   if (child->priv->next_sibling == NULL)
10036     self->priv->last_child = child;
10037 }
10038
10039 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10040                                            ClutterActor *child,
10041                                            gpointer      data);
10042
10043 typedef enum {
10044   ADD_CHILD_CREATE_META       = 1 << 0,
10045   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10046   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10047   ADD_CHILD_CHECK_STATE       = 1 << 3,
10048   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10049
10050   /* default flags for public API */
10051   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10052                                ADD_CHILD_EMIT_PARENT_SET |
10053                                ADD_CHILD_EMIT_ACTOR_ADDED |
10054                                ADD_CHILD_CHECK_STATE |
10055                                ADD_CHILD_NOTIFY_FIRST_LAST,
10056
10057   /* flags for legacy/deprecated API */
10058   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10059                                ADD_CHILD_CHECK_STATE |
10060                                ADD_CHILD_NOTIFY_FIRST_LAST
10061 } ClutterActorAddChildFlags;
10062
10063 /*< private >
10064  * clutter_actor_add_child_internal:
10065  * @self: a #ClutterActor
10066  * @child: a #ClutterActor
10067  * @flags: control flags for actions
10068  * @add_func: delegate function
10069  * @data: (closure): data to pass to @add_func
10070  *
10071  * Adds @child to the list of children of @self.
10072  *
10073  * The actual insertion inside the list is delegated to @add_func: this
10074  * function will just set up the state, perform basic checks, and emit
10075  * signals.
10076  *
10077  * The @flags argument is used to perform additional operations.
10078  */
10079 static inline void
10080 clutter_actor_add_child_internal (ClutterActor              *self,
10081                                   ClutterActor              *child,
10082                                   ClutterActorAddChildFlags  flags,
10083                                   ClutterActorAddChildFunc   add_func,
10084                                   gpointer                   data)
10085 {
10086   ClutterTextDirection text_dir;
10087   gboolean create_meta;
10088   gboolean emit_parent_set, emit_actor_added;
10089   gboolean check_state;
10090   gboolean notify_first_last;
10091   ClutterActor *old_first_child, *old_last_child;
10092
10093   if (child->priv->parent != NULL)
10094     {
10095       g_warning ("Cannot set a parent on an actor which has a parent. "
10096                  "You must use clutter_actor_remove_child() first.");
10097       return;
10098     }
10099
10100   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10101     {
10102       g_warning ("Cannot set a parent on a toplevel actor\n");
10103       return;
10104     }
10105
10106   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10107     {
10108       g_warning ("Cannot set a parent currently being destroyed");
10109       return;
10110     }
10111
10112   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10113   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10114   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10115   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10116   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10117
10118   old_first_child = self->priv->first_child;
10119   old_last_child = self->priv->last_child;
10120
10121   if (create_meta)
10122     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10123
10124   g_object_ref_sink (child);
10125   child->priv->parent = NULL;
10126   child->priv->next_sibling = NULL;
10127   child->priv->prev_sibling = NULL;
10128
10129   /* delegate the actual insertion */
10130   add_func (self, child, data);
10131
10132   g_assert (child->priv->parent == self);
10133
10134   self->priv->n_children += 1;
10135
10136   self->priv->age += 1;
10137
10138   /* if push_internal() has been called then we automatically set
10139    * the flag on the actor
10140    */
10141   if (self->priv->internal_child)
10142     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10143
10144   /* clutter_actor_reparent() will emit ::parent-set for us */
10145   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10146     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10147
10148   if (check_state)
10149     {
10150       /* If parent is mapped or realized, we need to also be mapped or
10151        * realized once we're inside the parent.
10152        */
10153       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10154
10155       /* propagate the parent's text direction to the child */
10156       text_dir = clutter_actor_get_text_direction (self);
10157       clutter_actor_set_text_direction (child, text_dir);
10158     }
10159
10160   if (child->priv->show_on_set_parent)
10161     clutter_actor_show (child);
10162
10163   if (CLUTTER_ACTOR_IS_MAPPED (child))
10164     clutter_actor_queue_redraw (child);
10165
10166   /* maintain the invariant that if an actor needs layout,
10167    * its parents do as well
10168    */
10169   if (child->priv->needs_width_request ||
10170       child->priv->needs_height_request ||
10171       child->priv->needs_allocation)
10172     {
10173       /* we work around the short-circuiting we do
10174        * in clutter_actor_queue_relayout() since we
10175        * want to force a relayout
10176        */
10177       child->priv->needs_width_request = TRUE;
10178       child->priv->needs_height_request = TRUE;
10179       child->priv->needs_allocation = TRUE;
10180
10181       clutter_actor_queue_relayout (child->priv->parent);
10182     }
10183
10184   if (emit_actor_added)
10185     g_signal_emit_by_name (self, "actor-added", child);
10186
10187   if (notify_first_last)
10188     {
10189       if (old_first_child != self->priv->first_child)
10190         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10191
10192       if (old_last_child != self->priv->last_child)
10193         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10194     }
10195 }
10196
10197 /**
10198  * clutter_actor_add_child:
10199  * @self: a #ClutterActor
10200  * @child: a #ClutterActor
10201  *
10202  * Adds @child to the children of @self.
10203  *
10204  * This function will acquire a reference on @child that will only
10205  * be released when calling clutter_actor_remove_child().
10206  *
10207  * This function will take into consideration the #ClutterActor:depth
10208  * of @child, and will keep the list of children sorted.
10209  *
10210  * This function will emit the #ClutterContainer::actor-added signal
10211  * on @self.
10212  *
10213  * Since: 1.10
10214  */
10215 void
10216 clutter_actor_add_child (ClutterActor *self,
10217                          ClutterActor *child)
10218 {
10219   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10220   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10221   g_return_if_fail (self != child);
10222   g_return_if_fail (child->priv->parent == NULL);
10223
10224   clutter_actor_add_child_internal (self, child,
10225                                     ADD_CHILD_DEFAULT_FLAGS,
10226                                     insert_child_at_depth,
10227                                     NULL);
10228 }
10229
10230 /**
10231  * clutter_actor_insert_child_at_index:
10232  * @self: a #ClutterActor
10233  * @child: a #ClutterActor
10234  * @index_: the index
10235  *
10236  * Inserts @child into the list of children of @self, using the
10237  * given @index_.
10238  *
10239  * This function will acquire a reference on @child that will only
10240  * be released when calling clutter_actor_remove_child().
10241  *
10242  * This function will not take into consideration the #ClutterActor:depth
10243  * of @child.
10244  *
10245  * This function will emit the #ClutterContainer::actor-added signal
10246  * on @self.
10247  *
10248  * Since: 1.10
10249  */
10250 void
10251 clutter_actor_insert_child_at_index (ClutterActor *self,
10252                                      ClutterActor *child,
10253                                      gint          index_)
10254 {
10255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10256   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10257   g_return_if_fail (self != child);
10258   g_return_if_fail (child->priv->parent == NULL);
10259
10260   clutter_actor_add_child_internal (self, child,
10261                                     ADD_CHILD_DEFAULT_FLAGS,
10262                                     insert_child_at_index,
10263                                     GINT_TO_POINTER (index_));
10264 }
10265
10266 /**
10267  * clutter_actor_insert_child_above:
10268  * @self: a #ClutterActor
10269  * @child: a #ClutterActor
10270  * @sibling: (allow-none): a child of @self, or %NULL
10271  *
10272  * Inserts @child into the list of children of @self, above another
10273  * child of @self or, if @sibling is %NULL, above all the children
10274  * of @self.
10275  *
10276  * This function will acquire a reference on @child that will only
10277  * be released when calling clutter_actor_remove_child().
10278  *
10279  * This function will not take into consideration the #ClutterActor:depth
10280  * of @child.
10281  *
10282  * This function will emit the #ClutterContainer::actor-added signal
10283  * on @self.
10284  *
10285  * Since: 1.10
10286  */
10287 void
10288 clutter_actor_insert_child_above (ClutterActor *self,
10289                                   ClutterActor *child,
10290                                   ClutterActor *sibling)
10291 {
10292   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10293   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10294   g_return_if_fail (self != child);
10295   g_return_if_fail (child != sibling);
10296   g_return_if_fail (child->priv->parent == NULL);
10297   g_return_if_fail (sibling == NULL ||
10298                     (CLUTTER_IS_ACTOR (sibling) &&
10299                      sibling->priv->parent == self));
10300
10301   clutter_actor_add_child_internal (self, child,
10302                                     ADD_CHILD_DEFAULT_FLAGS,
10303                                     insert_child_above,
10304                                     sibling);
10305 }
10306
10307 /**
10308  * clutter_actor_insert_child_below:
10309  * @self: a #ClutterActor
10310  * @child: a #ClutterActor
10311  * @sibling: (allow-none): a child of @self, or %NULL
10312  *
10313  * Inserts @child into the list of children of @self, below another
10314  * child of @self or, if @sibling is %NULL, below all the children
10315  * of @self.
10316  *
10317  * This function will acquire a reference on @child that will only
10318  * be released when calling clutter_actor_remove_child().
10319  *
10320  * This function will not take into consideration the #ClutterActor:depth
10321  * of @child.
10322  *
10323  * This function will emit the #ClutterContainer::actor-added signal
10324  * on @self.
10325  *
10326  * Since: 1.10
10327  */
10328 void
10329 clutter_actor_insert_child_below (ClutterActor *self,
10330                                   ClutterActor *child,
10331                                   ClutterActor *sibling)
10332 {
10333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10334   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10335   g_return_if_fail (self != child);
10336   g_return_if_fail (child != sibling);
10337   g_return_if_fail (child->priv->parent == NULL);
10338   g_return_if_fail (sibling == NULL ||
10339                     (CLUTTER_IS_ACTOR (sibling) &&
10340                      sibling->priv->parent == self));
10341
10342   clutter_actor_add_child_internal (self, child,
10343                                     ADD_CHILD_DEFAULT_FLAGS,
10344                                     insert_child_below,
10345                                     sibling);
10346 }
10347
10348 /**
10349  * clutter_actor_set_parent:
10350  * @self: A #ClutterActor
10351  * @parent: A new #ClutterActor parent
10352  *
10353  * Sets the parent of @self to @parent.
10354  *
10355  * This function will result in @parent acquiring a reference on @self,
10356  * eventually by sinking its floating reference first. The reference
10357  * will be released by clutter_actor_unparent().
10358  *
10359  * This function should only be called by legacy #ClutterActor<!-- -->s
10360  * implementing the #ClutterContainer interface.
10361  *
10362  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10363  */
10364 void
10365 clutter_actor_set_parent (ClutterActor *self,
10366                           ClutterActor *parent)
10367 {
10368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10369   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10370   g_return_if_fail (self != parent);
10371   g_return_if_fail (self->priv->parent == NULL);
10372
10373   /* as this function will be called inside ClutterContainer::add
10374    * implementations or when building up a composite actor, we have
10375    * to preserve the old behaviour, and not create child meta or
10376    * emit the ::actor-added signal, to avoid recursion or double
10377    * emissions
10378    */
10379   clutter_actor_add_child_internal (parent, self,
10380                                     ADD_CHILD_LEGACY_FLAGS,
10381                                     insert_child_at_depth,
10382                                     NULL);
10383 }
10384
10385 /**
10386  * clutter_actor_get_parent:
10387  * @self: A #ClutterActor
10388  *
10389  * Retrieves the parent of @self.
10390  *
10391  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10392  *  if no parent is set
10393  */
10394 ClutterActor *
10395 clutter_actor_get_parent (ClutterActor *self)
10396 {
10397   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10398
10399   return self->priv->parent;
10400 }
10401
10402 /**
10403  * clutter_actor_get_paint_visibility:
10404  * @self: A #ClutterActor
10405  *
10406  * Retrieves the 'paint' visibility of an actor recursively checking for non
10407  * visible parents.
10408  *
10409  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10410  *
10411  * Return Value: %TRUE if the actor is visibile and will be painted.
10412  *
10413  * Since: 0.8.4
10414  */
10415 gboolean
10416 clutter_actor_get_paint_visibility (ClutterActor *actor)
10417 {
10418   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10419
10420   return CLUTTER_ACTOR_IS_MAPPED (actor);
10421 }
10422
10423 /**
10424  * clutter_actor_remove_child:
10425  * @self: a #ClutterActor
10426  * @child: a #ClutterActor
10427  *
10428  * Removes @child from the children of @self.
10429  *
10430  * This function will release the reference added by
10431  * clutter_actor_add_child(), so if you want to keep using @child
10432  * you will have to acquire a referenced on it before calling this
10433  * function.
10434  *
10435  * This function will emit the #ClutterContainer::actor-removed
10436  * signal on @self.
10437  *
10438  * Since: 1.10
10439  */
10440 void
10441 clutter_actor_remove_child (ClutterActor *self,
10442                             ClutterActor *child)
10443 {
10444   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10445   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10446   g_return_if_fail (self != child);
10447   g_return_if_fail (child->priv->parent != NULL);
10448   g_return_if_fail (child->priv->parent == self);
10449
10450   clutter_actor_remove_child_internal (self, child,
10451                                        REMOVE_CHILD_DEFAULT_FLAGS);
10452 }
10453
10454 /**
10455  * clutter_actor_remove_all_children:
10456  * @self: a #ClutterActor
10457  *
10458  * Removes all children of @self.
10459  *
10460  * This function releases the reference added by inserting a child actor
10461  * in the list of children of @self.
10462  *
10463  * Since: 1.10
10464  */
10465 void
10466 clutter_actor_remove_all_children (ClutterActor *self)
10467 {
10468   ClutterActor *iter;
10469
10470   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10471
10472   if (self->priv->n_children == 0)
10473     return;
10474
10475   iter = self->priv->first_child;
10476   while (iter != NULL)
10477     {
10478       ClutterActor *next = iter->priv->next_sibling;
10479
10480       clutter_actor_remove_child_internal (self, iter,
10481                                            REMOVE_CHILD_DEFAULT_FLAGS);
10482
10483       iter = next;
10484     }
10485
10486   g_assert (self->priv->first_child == NULL);
10487   g_assert (self->priv->last_child == NULL);
10488   g_assert (self->priv->n_children == 0);
10489 }
10490
10491 typedef struct _InsertBetweenData {
10492   ClutterActor *prev_sibling;
10493   ClutterActor *next_sibling;
10494 } InsertBetweenData;
10495
10496 static void
10497 insert_child_between (ClutterActor *self,
10498                       ClutterActor *child,
10499                       gpointer      data_)
10500 {
10501   InsertBetweenData *data = data_;
10502   ClutterActor *prev_sibling = data->prev_sibling;
10503   ClutterActor *next_sibling = data->next_sibling;
10504
10505   child->priv->parent = self;
10506   child->priv->prev_sibling = prev_sibling;
10507   child->priv->next_sibling = next_sibling;
10508
10509   if (prev_sibling != NULL)
10510     prev_sibling->priv->next_sibling = child;
10511
10512   if (next_sibling != NULL)
10513     next_sibling->priv->prev_sibling = child;
10514
10515   if (child->priv->prev_sibling == NULL)
10516     self->priv->first_child = child;
10517
10518   if (child->priv->next_sibling == NULL)
10519     self->priv->last_child = child;
10520 }
10521
10522 /**
10523  * clutter_actor_replace_child:
10524  * @self: a #ClutterActor
10525  * @old_child: the child of @self to replace
10526  * @new_child: the #ClutterActor to replace @old_child
10527  *
10528  * Replaces @old_child with @new_child in the list of children of @self.
10529  *
10530  * Since: 1.10
10531  */
10532 void
10533 clutter_actor_replace_child (ClutterActor *self,
10534                              ClutterActor *old_child,
10535                              ClutterActor *new_child)
10536 {
10537   ClutterActor *prev_sibling, *next_sibling;
10538   InsertBetweenData clos;
10539
10540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10541   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10542   g_return_if_fail (old_child->priv->parent == self);
10543   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10544   g_return_if_fail (old_child != new_child);
10545   g_return_if_fail (new_child != self);
10546   g_return_if_fail (new_child->priv->parent == NULL);
10547
10548   prev_sibling = old_child->priv->prev_sibling;
10549   next_sibling = old_child->priv->next_sibling;
10550   clutter_actor_remove_child_internal (self, old_child,
10551                                        REMOVE_CHILD_DEFAULT_FLAGS);
10552
10553   clos.prev_sibling = prev_sibling;
10554   clos.next_sibling = next_sibling;
10555   clutter_actor_add_child_internal (self, new_child,
10556                                     ADD_CHILD_DEFAULT_FLAGS,
10557                                     insert_child_between,
10558                                     &clos);
10559 }
10560
10561 /**
10562  * clutter_actor_unparent:
10563  * @self: a #ClutterActor
10564  *
10565  * Removes the parent of @self.
10566  *
10567  * This will cause the parent of @self to release the reference
10568  * acquired when calling clutter_actor_set_parent(), so if you
10569  * want to keep @self you will have to acquire a reference of
10570  * your own, through g_object_ref().
10571  *
10572  * This function should only be called by legacy #ClutterActor<!-- -->s
10573  * implementing the #ClutterContainer interface.
10574  *
10575  * Since: 0.1.1
10576  *
10577  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10578  */
10579 void
10580 clutter_actor_unparent (ClutterActor *self)
10581 {
10582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10583
10584   if (self->priv->parent == NULL)
10585     return;
10586
10587   clutter_actor_remove_child_internal (self->priv->parent, self,
10588                                        REMOVE_CHILD_LEGACY_FLAGS);
10589 }
10590
10591 /**
10592  * clutter_actor_reparent:
10593  * @self: a #ClutterActor
10594  * @new_parent: the new #ClutterActor parent
10595  *
10596  * Resets the parent actor of @self.
10597  *
10598  * This function is logically equivalent to calling clutter_actor_unparent()
10599  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10600  * ensures the child is not finalized when unparented, and emits the
10601  * #ClutterActor::parent-set signal only once.
10602  *
10603  * In reality, calling this function is less useful than it sounds, as some
10604  * application code may rely on changes in the intermediate state between
10605  * removal and addition of the actor from its old parent to the @new_parent.
10606  * Thus, it is strongly encouraged to avoid using this function in application
10607  * code.
10608  *
10609  * Since: 0.2
10610  *
10611  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10612  *   clutter_actor_add_child() instead; remember to take a reference on
10613  *   the actor being removed before calling clutter_actor_remove_child()
10614  *   to avoid the reference count dropping to zero and the actor being
10615  *   destroyed.
10616  */
10617 void
10618 clutter_actor_reparent (ClutterActor *self,
10619                         ClutterActor *new_parent)
10620 {
10621   ClutterActorPrivate *priv;
10622
10623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10624   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10625   g_return_if_fail (self != new_parent);
10626
10627   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10628     {
10629       g_warning ("Cannot set a parent on a toplevel actor");
10630       return;
10631     }
10632
10633   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10634     {
10635       g_warning ("Cannot set a parent currently being destroyed");
10636       return;
10637     }
10638
10639   priv = self->priv;
10640
10641   if (priv->parent != new_parent)
10642     {
10643       ClutterActor *old_parent;
10644
10645       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10646
10647       old_parent = priv->parent;
10648
10649       g_object_ref (self);
10650
10651       if (old_parent != NULL)
10652         {
10653          /* go through the Container implementation if this is a regular
10654           * child and not an internal one
10655           */
10656          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10657            {
10658              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10659
10660              /* this will have to call unparent() */
10661              clutter_container_remove_actor (parent, self);
10662            }
10663          else
10664            clutter_actor_remove_child_internal (old_parent, self,
10665                                                 REMOVE_CHILD_LEGACY_FLAGS);
10666         }
10667
10668       /* Note, will call set_parent() */
10669       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10670         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10671       else
10672         clutter_actor_add_child_internal (new_parent, self,
10673                                           ADD_CHILD_LEGACY_FLAGS,
10674                                           insert_child_at_depth,
10675                                           NULL);
10676
10677       /* we emit the ::parent-set signal once */
10678       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10679
10680       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10681
10682       /* the IN_REPARENT flag suspends state updates */
10683       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10684
10685       g_object_unref (self);
10686    }
10687 }
10688
10689 /**
10690  * clutter_actor_contains:
10691  * @self: A #ClutterActor
10692  * @descendant: A #ClutterActor, possibly contained in @self
10693  *
10694  * Determines if @descendant is contained inside @self (either as an
10695  * immediate child, or as a deeper descendant). If @self and
10696  * @descendant point to the same actor then it will also return %TRUE.
10697  *
10698  * Return value: whether @descendent is contained within @self
10699  *
10700  * Since: 1.4
10701  */
10702 gboolean
10703 clutter_actor_contains (ClutterActor *self,
10704                         ClutterActor *descendant)
10705 {
10706   ClutterActor *actor;
10707
10708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10709   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10710
10711   for (actor = descendant; actor; actor = actor->priv->parent)
10712     if (actor == self)
10713       return TRUE;
10714
10715   return FALSE;
10716 }
10717
10718 /**
10719  * clutter_actor_set_child_above_sibling:
10720  * @self: a #ClutterActor
10721  * @child: a #ClutterActor child of @self
10722  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10723  *
10724  * Sets @child to be above @sibling in the list of children of @self.
10725  *
10726  * If @sibling is %NULL, @child will be the new last child of @self.
10727  *
10728  * This function is logically equivalent to removing @child and using
10729  * clutter_actor_insert_child_above(), but it will not emit signals
10730  * or change state on @child.
10731  *
10732  * Since: 1.10
10733  */
10734 void
10735 clutter_actor_set_child_above_sibling (ClutterActor *self,
10736                                        ClutterActor *child,
10737                                        ClutterActor *sibling)
10738 {
10739   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10740   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10741   g_return_if_fail (child->priv->parent == self);
10742   g_return_if_fail (child != sibling);
10743   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10744
10745   if (sibling != NULL)
10746     g_return_if_fail (sibling->priv->parent == self);
10747
10748   /* we don't want to change the state of child, or emit signals, or
10749    * regenerate ChildMeta instances here, but we still want to follow
10750    * the correct sequence of steps encoded in remove_child() and
10751    * add_child(), so that correctness is ensured, and we only go
10752    * through one known code path.
10753    */
10754   g_object_ref (child);
10755   clutter_actor_remove_child_internal (self, child, 0);
10756   clutter_actor_add_child_internal (self, child,
10757                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10758                                     insert_child_above,
10759                                     sibling);
10760
10761   clutter_actor_queue_relayout (self);
10762 }
10763
10764 /**
10765  * clutter_actor_set_child_below_sibling:
10766  * @self: a #ClutterActor
10767  * @child: a #ClutterActor child of @self
10768  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10769  *
10770  * Sets @child to be below @sibling in the list of children of @self.
10771  *
10772  * If @sibling is %NULL, @child will be the new first child of @self.
10773  *
10774  * This function is logically equivalent to removing @self and using
10775  * clutter_actor_insert_child_below(), but it will not emit signals
10776  * or change state on @child.
10777  *
10778  * Since: 1.10
10779  */
10780 void
10781 clutter_actor_set_child_below_sibling (ClutterActor *self,
10782                                        ClutterActor *child,
10783                                        ClutterActor *sibling)
10784 {
10785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10786   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10787   g_return_if_fail (child->priv->parent == self);
10788   g_return_if_fail (child != sibling);
10789   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10790
10791   if (sibling != NULL)
10792     g_return_if_fail (sibling->priv->parent == self);
10793
10794   /* see the comment in set_child_above_sibling() */
10795   g_object_ref (child);
10796   clutter_actor_remove_child_internal (self, child, 0);
10797   clutter_actor_add_child_internal (self, child,
10798                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10799                                     insert_child_below,
10800                                     sibling);
10801
10802   clutter_actor_queue_relayout (self);
10803 }
10804
10805 /**
10806  * clutter_actor_set_child_at_index:
10807  * @self: a #ClutterActor
10808  * @child: a #ClutterActor child of @self
10809  * @index_: the new index for @child
10810  *
10811  * Changes the index of @child in the list of children of @self.
10812  *
10813  * This function is logically equivalent to removing @child and
10814  * calling clutter_actor_insert_child_at_index(), but it will not
10815  * emit signals or change state on @child.
10816  *
10817  * Since: 1.10
10818  */
10819 void
10820 clutter_actor_set_child_at_index (ClutterActor *self,
10821                                   ClutterActor *child,
10822                                   gint          index_)
10823 {
10824   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10825   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10826   g_return_if_fail (child->priv->parent == self);
10827   g_return_if_fail (index_ <= self->priv->n_children);
10828
10829   g_object_ref (child);
10830   clutter_actor_remove_child_internal (self, child, 0);
10831   clutter_actor_add_child_internal (self, child,
10832                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10833                                     insert_child_at_index,
10834                                     GINT_TO_POINTER (index_));
10835
10836   clutter_actor_queue_relayout (self);
10837 }
10838
10839 /**
10840  * clutter_actor_raise:
10841  * @self: A #ClutterActor
10842  * @below: (allow-none): A #ClutterActor to raise above.
10843  *
10844  * Puts @self above @below.
10845  *
10846  * Both actors must have the same parent, and the parent must implement
10847  * the #ClutterContainer interface
10848  *
10849  * This function calls clutter_container_raise_child() internally.
10850  *
10851  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10852  */
10853 void
10854 clutter_actor_raise (ClutterActor *self,
10855                      ClutterActor *below)
10856 {
10857   ClutterActor *parent;
10858
10859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10860
10861   parent = clutter_actor_get_parent (self);
10862   if (parent == NULL)
10863     {
10864       g_warning ("%s: Actor '%s' is not inside a container",
10865                  G_STRFUNC,
10866                  _clutter_actor_get_debug_name (self));
10867       return;
10868     }
10869
10870   if (below != NULL)
10871     {
10872       if (parent != clutter_actor_get_parent (below))
10873         {
10874           g_warning ("%s Actor '%s' is not in the same container as "
10875                      "actor '%s'",
10876                      G_STRFUNC,
10877                      _clutter_actor_get_debug_name (self),
10878                      _clutter_actor_get_debug_name (below));
10879           return;
10880         }
10881     }
10882
10883   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10884 }
10885
10886 /**
10887  * clutter_actor_lower:
10888  * @self: A #ClutterActor
10889  * @above: (allow-none): A #ClutterActor to lower below
10890  *
10891  * Puts @self below @above.
10892  *
10893  * Both actors must have the same parent, and the parent must implement
10894  * the #ClutterContainer interface.
10895  *
10896  * This function calls clutter_container_lower_child() internally.
10897  *
10898  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10899  */
10900 void
10901 clutter_actor_lower (ClutterActor *self,
10902                      ClutterActor *above)
10903 {
10904   ClutterActor *parent;
10905
10906   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10907
10908   parent = clutter_actor_get_parent (self);
10909   if (parent == NULL)
10910     {
10911       g_warning ("%s: Actor of type %s is not inside a container",
10912                  G_STRFUNC,
10913                  _clutter_actor_get_debug_name (self));
10914       return;
10915     }
10916
10917   if (above)
10918     {
10919       if (parent != clutter_actor_get_parent (above))
10920         {
10921           g_warning ("%s: Actor '%s' is not in the same container as "
10922                      "actor '%s'",
10923                      G_STRFUNC,
10924                      _clutter_actor_get_debug_name (self),
10925                      _clutter_actor_get_debug_name (above));
10926           return;
10927         }
10928     }
10929
10930   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
10931 }
10932
10933 /**
10934  * clutter_actor_raise_top:
10935  * @self: A #ClutterActor
10936  *
10937  * Raises @self to the top.
10938  *
10939  * This function calls clutter_actor_raise() internally.
10940  *
10941  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
10942  *   a %NULL sibling, instead.
10943  */
10944 void
10945 clutter_actor_raise_top (ClutterActor *self)
10946 {
10947   clutter_actor_raise (self, NULL);
10948 }
10949
10950 /**
10951  * clutter_actor_lower_bottom:
10952  * @self: A #ClutterActor
10953  *
10954  * Lowers @self to the bottom.
10955  *
10956  * This function calls clutter_actor_lower() internally.
10957  *
10958  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
10959  *   a %NULL sibling, instead.
10960  */
10961 void
10962 clutter_actor_lower_bottom (ClutterActor *self)
10963 {
10964   clutter_actor_lower (self, NULL);
10965 }
10966
10967 /*
10968  * Event handling
10969  */
10970
10971 /**
10972  * clutter_actor_event:
10973  * @actor: a #ClutterActor
10974  * @event: a #ClutterEvent
10975  * @capture: TRUE if event in in capture phase, FALSE otherwise.
10976  *
10977  * This function is used to emit an event on the main stage.
10978  * You should rarely need to use this function, except for
10979  * synthetising events.
10980  *
10981  * Return value: the return value from the signal emission: %TRUE
10982  *   if the actor handled the event, or %FALSE if the event was
10983  *   not handled
10984  *
10985  * Since: 0.6
10986  */
10987 gboolean
10988 clutter_actor_event (ClutterActor *actor,
10989                      ClutterEvent *event,
10990                      gboolean      capture)
10991 {
10992   gboolean retval = FALSE;
10993   gint signal_num = -1;
10994
10995   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10996   g_return_val_if_fail (event != NULL, FALSE);
10997
10998   g_object_ref (actor);
10999
11000   if (capture)
11001     {
11002       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11003                      event,
11004                      &retval);
11005       goto out;
11006     }
11007
11008   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11009
11010   if (!retval)
11011     {
11012       switch (event->type)
11013         {
11014         case CLUTTER_NOTHING:
11015           break;
11016         case CLUTTER_BUTTON_PRESS:
11017           signal_num = BUTTON_PRESS_EVENT;
11018           break;
11019         case CLUTTER_BUTTON_RELEASE:
11020           signal_num = BUTTON_RELEASE_EVENT;
11021           break;
11022         case CLUTTER_SCROLL:
11023           signal_num = SCROLL_EVENT;
11024           break;
11025         case CLUTTER_KEY_PRESS:
11026           signal_num = KEY_PRESS_EVENT;
11027           break;
11028         case CLUTTER_KEY_RELEASE:
11029           signal_num = KEY_RELEASE_EVENT;
11030           break;
11031         case CLUTTER_MOTION:
11032           signal_num = MOTION_EVENT;
11033           break;
11034         case CLUTTER_ENTER:
11035           signal_num = ENTER_EVENT;
11036           break;
11037         case CLUTTER_LEAVE:
11038           signal_num = LEAVE_EVENT;
11039           break;
11040         case CLUTTER_DELETE:
11041         case CLUTTER_DESTROY_NOTIFY:
11042         case CLUTTER_CLIENT_MESSAGE:
11043         default:
11044           signal_num = -1;
11045           break;
11046         }
11047
11048       if (signal_num != -1)
11049         g_signal_emit (actor, actor_signals[signal_num], 0,
11050                        event, &retval);
11051     }
11052
11053 out:
11054   g_object_unref (actor);
11055
11056   return retval;
11057 }
11058
11059 /**
11060  * clutter_actor_set_reactive:
11061  * @actor: a #ClutterActor
11062  * @reactive: whether the actor should be reactive to events
11063  *
11064  * Sets @actor as reactive. Reactive actors will receive events.
11065  *
11066  * Since: 0.6
11067  */
11068 void
11069 clutter_actor_set_reactive (ClutterActor *actor,
11070                             gboolean      reactive)
11071 {
11072   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11073
11074   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11075     return;
11076
11077   if (reactive)
11078     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11079   else
11080     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11081
11082   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11083 }
11084
11085 /**
11086  * clutter_actor_get_reactive:
11087  * @actor: a #ClutterActor
11088  *
11089  * Checks whether @actor is marked as reactive.
11090  *
11091  * Return value: %TRUE if the actor is reactive
11092  *
11093  * Since: 0.6
11094  */
11095 gboolean
11096 clutter_actor_get_reactive (ClutterActor *actor)
11097 {
11098   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11099
11100   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11101 }
11102
11103 /**
11104  * clutter_actor_get_anchor_point:
11105  * @self: a #ClutterActor
11106  * @anchor_x: (out): return location for the X coordinate of the anchor point
11107  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11108  *
11109  * Gets the current anchor point of the @actor in pixels.
11110  *
11111  * Since: 0.6
11112  */
11113 void
11114 clutter_actor_get_anchor_point (ClutterActor *self,
11115                                 gfloat       *anchor_x,
11116                                 gfloat       *anchor_y)
11117 {
11118   const ClutterTransformInfo *info;
11119
11120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11121
11122   info = _clutter_actor_get_transform_info_or_defaults (self);
11123   clutter_anchor_coord_get_units (self, &info->anchor,
11124                                   anchor_x,
11125                                   anchor_y,
11126                                   NULL);
11127 }
11128
11129 /**
11130  * clutter_actor_set_anchor_point:
11131  * @self: a #ClutterActor
11132  * @anchor_x: X coordinate of the anchor point
11133  * @anchor_y: Y coordinate of the anchor point
11134  *
11135  * Sets an anchor point for @self. The anchor point is a point in the
11136  * coordinate space of an actor to which the actor position within its
11137  * parent is relative; the default is (0, 0), i.e. the top-left corner
11138  * of the actor.
11139  *
11140  * Since: 0.6
11141  */
11142 void
11143 clutter_actor_set_anchor_point (ClutterActor *self,
11144                                 gfloat        anchor_x,
11145                                 gfloat        anchor_y)
11146 {
11147   ClutterTransformInfo *info;
11148   ClutterActorPrivate *priv;
11149   gboolean changed = FALSE;
11150   gfloat old_anchor_x, old_anchor_y;
11151   GObject *obj;
11152
11153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11154
11155   obj = G_OBJECT (self);
11156   priv = self->priv;
11157   info = _clutter_actor_get_transform_info (self);
11158
11159   g_object_freeze_notify (obj);
11160
11161   clutter_anchor_coord_get_units (self, &info->anchor,
11162                                   &old_anchor_x,
11163                                   &old_anchor_y,
11164                                   NULL);
11165
11166   if (info->anchor.is_fractional)
11167     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11168
11169   if (old_anchor_x != anchor_x)
11170     {
11171       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11172       changed = TRUE;
11173     }
11174
11175   if (old_anchor_y != anchor_y)
11176     {
11177       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11178       changed = TRUE;
11179     }
11180
11181   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11182
11183   if (changed)
11184     {
11185       priv->transform_valid = FALSE;
11186       clutter_actor_queue_redraw (self);
11187     }
11188
11189   g_object_thaw_notify (obj);
11190 }
11191
11192 /**
11193  * clutter_actor_get_anchor_point_gravity:
11194  * @self: a #ClutterActor
11195  *
11196  * Retrieves the anchor position expressed as a #ClutterGravity. If
11197  * the anchor point was specified using pixels or units this will
11198  * return %CLUTTER_GRAVITY_NONE.
11199  *
11200  * Return value: the #ClutterGravity used by the anchor point
11201  *
11202  * Since: 1.0
11203  */
11204 ClutterGravity
11205 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11206 {
11207   const ClutterTransformInfo *info;
11208
11209   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11210
11211   info = _clutter_actor_get_transform_info_or_defaults (self);
11212
11213   return clutter_anchor_coord_get_gravity (&info->anchor);
11214 }
11215
11216 /**
11217  * clutter_actor_move_anchor_point:
11218  * @self: a #ClutterActor
11219  * @anchor_x: X coordinate of the anchor point
11220  * @anchor_y: Y coordinate of the anchor point
11221  *
11222  * Sets an anchor point for the actor, and adjusts the actor postion so that
11223  * the relative position of the actor toward its parent remains the same.
11224  *
11225  * Since: 0.6
11226  */
11227 void
11228 clutter_actor_move_anchor_point (ClutterActor *self,
11229                                  gfloat        anchor_x,
11230                                  gfloat        anchor_y)
11231 {
11232   gfloat old_anchor_x, old_anchor_y;
11233   const ClutterTransformInfo *info;
11234
11235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11236
11237   info = _clutter_actor_get_transform_info (self);
11238   clutter_anchor_coord_get_units (self, &info->anchor,
11239                                   &old_anchor_x,
11240                                   &old_anchor_y,
11241                                   NULL);
11242
11243   g_object_freeze_notify (G_OBJECT (self));
11244
11245   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11246
11247   if (self->priv->position_set)
11248     clutter_actor_move_by (self,
11249                            anchor_x - old_anchor_x,
11250                            anchor_y - old_anchor_y);
11251
11252   g_object_thaw_notify (G_OBJECT (self));
11253 }
11254
11255 /**
11256  * clutter_actor_move_anchor_point_from_gravity:
11257  * @self: a #ClutterActor
11258  * @gravity: #ClutterGravity.
11259  *
11260  * Sets an anchor point on the actor based on the given gravity, adjusting the
11261  * actor postion so that its relative position within its parent remains
11262  * unchanged.
11263  *
11264  * Since version 1.0 the anchor point will be stored as a gravity so
11265  * that if the actor changes size then the anchor point will move. For
11266  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11267  * and later double the size of the actor, the anchor point will move
11268  * to the bottom right.
11269  *
11270  * Since: 0.6
11271  */
11272 void
11273 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11274                                               ClutterGravity  gravity)
11275 {
11276   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11277   const ClutterTransformInfo *info;
11278   ClutterActorPrivate *priv;
11279
11280   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11281
11282   priv = self->priv;
11283   info = _clutter_actor_get_transform_info (self);
11284
11285   g_object_freeze_notify (G_OBJECT (self));
11286
11287   clutter_anchor_coord_get_units (self, &info->anchor,
11288                                   &old_anchor_x,
11289                                   &old_anchor_y,
11290                                   NULL);
11291   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11292   clutter_anchor_coord_get_units (self, &info->anchor,
11293                                   &new_anchor_x,
11294                                   &new_anchor_y,
11295                                   NULL);
11296
11297   if (priv->position_set)
11298     clutter_actor_move_by (self,
11299                            new_anchor_x - old_anchor_x,
11300                            new_anchor_y - old_anchor_y);
11301
11302   g_object_thaw_notify (G_OBJECT (self));
11303 }
11304
11305 /**
11306  * clutter_actor_set_anchor_point_from_gravity:
11307  * @self: a #ClutterActor
11308  * @gravity: #ClutterGravity.
11309  *
11310  * Sets an anchor point on the actor, based on the given gravity (this is a
11311  * convenience function wrapping clutter_actor_set_anchor_point()).
11312  *
11313  * Since version 1.0 the anchor point will be stored as a gravity so
11314  * that if the actor changes size then the anchor point will move. For
11315  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11316  * and later double the size of the actor, the anchor point will move
11317  * to the bottom right.
11318  *
11319  * Since: 0.6
11320  */
11321 void
11322 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11323                                              ClutterGravity  gravity)
11324 {
11325   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11326
11327   if (gravity == CLUTTER_GRAVITY_NONE)
11328     clutter_actor_set_anchor_point (self, 0, 0);
11329   else
11330     {
11331       GObject *obj = G_OBJECT (self);
11332       ClutterTransformInfo *info;
11333
11334       g_object_freeze_notify (obj);
11335
11336       info = _clutter_actor_get_transform_info (self);
11337       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11338
11339       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11340       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11341       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11342
11343       self->priv->transform_valid = FALSE;
11344
11345       clutter_actor_queue_redraw (self);
11346
11347       g_object_thaw_notify (obj);
11348     }
11349 }
11350
11351 static void
11352 clutter_container_iface_init (ClutterContainerIface *iface)
11353 {
11354   /* we don't override anything, as ClutterContainer already has a default
11355    * implementation that we can use, and which calls into our own API.
11356    */
11357 }
11358
11359 typedef enum
11360 {
11361   PARSE_X,
11362   PARSE_Y,
11363   PARSE_WIDTH,
11364   PARSE_HEIGHT,
11365   PARSE_ANCHOR_X,
11366   PARSE_ANCHOR_Y
11367 } ParseDimension;
11368
11369 static gfloat
11370 parse_units (ClutterActor   *self,
11371              ParseDimension  dimension,
11372              JsonNode       *node)
11373 {
11374   GValue value = { 0, };
11375   gfloat retval = 0;
11376
11377   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11378     return 0;
11379
11380   json_node_get_value (node, &value);
11381
11382   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11383     {
11384       retval = (gfloat) g_value_get_int64 (&value);
11385     }
11386   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11387     {
11388       retval = g_value_get_double (&value);
11389     }
11390   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11391     {
11392       ClutterUnits units;
11393       gboolean res;
11394
11395       res = clutter_units_from_string (&units, g_value_get_string (&value));
11396       if (res)
11397         retval = clutter_units_to_pixels (&units);
11398       else
11399         {
11400           g_warning ("Invalid value '%s': integers, strings or floating point "
11401                      "values can be used for the x, y, width and height "
11402                      "properties. Valid modifiers for strings are 'px', 'mm', "
11403                      "'pt' and 'em'.",
11404                      g_value_get_string (&value));
11405           retval = 0;
11406         }
11407     }
11408   else
11409     {
11410       g_warning ("Invalid value of type '%s': integers, strings of floating "
11411                  "point values can be used for the x, y, width, height "
11412                  "anchor-x and anchor-y properties.",
11413                  g_type_name (G_VALUE_TYPE (&value)));
11414     }
11415
11416   g_value_unset (&value);
11417
11418   return retval;
11419 }
11420
11421 typedef struct {
11422   ClutterRotateAxis axis;
11423
11424   gdouble angle;
11425
11426   gfloat center_x;
11427   gfloat center_y;
11428   gfloat center_z;
11429 } RotationInfo;
11430
11431 static inline gboolean
11432 parse_rotation_array (ClutterActor *actor,
11433                       JsonArray    *array,
11434                       RotationInfo *info)
11435 {
11436   JsonNode *element;
11437
11438   if (json_array_get_length (array) != 2)
11439     return FALSE;
11440
11441   /* angle */
11442   element = json_array_get_element (array, 0);
11443   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11444     info->angle = json_node_get_double (element);
11445   else
11446     return FALSE;
11447
11448   /* center */
11449   element = json_array_get_element (array, 1);
11450   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11451     {
11452       JsonArray *center = json_node_get_array (element);
11453
11454       if (json_array_get_length (center) != 2)
11455         return FALSE;
11456
11457       switch (info->axis)
11458         {
11459         case CLUTTER_X_AXIS:
11460           info->center_y = parse_units (actor, PARSE_Y,
11461                                         json_array_get_element (center, 0));
11462           info->center_z = parse_units (actor, PARSE_Y,
11463                                         json_array_get_element (center, 1));
11464           return TRUE;
11465
11466         case CLUTTER_Y_AXIS:
11467           info->center_x = parse_units (actor, PARSE_X,
11468                                         json_array_get_element (center, 0));
11469           info->center_z = parse_units (actor, PARSE_X,
11470                                         json_array_get_element (center, 1));
11471           return TRUE;
11472
11473         case CLUTTER_Z_AXIS:
11474           info->center_x = parse_units (actor, PARSE_X,
11475                                         json_array_get_element (center, 0));
11476           info->center_y = parse_units (actor, PARSE_Y,
11477                                         json_array_get_element (center, 1));
11478           return TRUE;
11479         }
11480     }
11481
11482   return FALSE;
11483 }
11484
11485 static gboolean
11486 parse_rotation (ClutterActor *actor,
11487                 JsonNode     *node,
11488                 RotationInfo *info)
11489 {
11490   JsonArray *array;
11491   guint len, i;
11492   gboolean retval = FALSE;
11493
11494   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11495     {
11496       g_warning ("Invalid node of type '%s' found, expecting an array",
11497                  json_node_type_name (node));
11498       return FALSE;
11499     }
11500
11501   array = json_node_get_array (node);
11502   len = json_array_get_length (array);
11503
11504   for (i = 0; i < len; i++)
11505     {
11506       JsonNode *element = json_array_get_element (array, i);
11507       JsonObject *object;
11508       JsonNode *member;
11509
11510       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11511         {
11512           g_warning ("Invalid node of type '%s' found, expecting an object",
11513                      json_node_type_name (element));
11514           return FALSE;
11515         }
11516
11517       object = json_node_get_object (element);
11518
11519       if (json_object_has_member (object, "x-axis"))
11520         {
11521           member = json_object_get_member (object, "x-axis");
11522
11523           info->axis = CLUTTER_X_AXIS;
11524
11525           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11526             {
11527               info->angle = json_node_get_double (member);
11528               retval = TRUE;
11529             }
11530           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11531             retval = parse_rotation_array (actor,
11532                                            json_node_get_array (member),
11533                                            info);
11534           else
11535             retval = FALSE;
11536         }
11537       else if (json_object_has_member (object, "y-axis"))
11538         {
11539           member = json_object_get_member (object, "y-axis");
11540
11541           info->axis = CLUTTER_Y_AXIS;
11542
11543           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11544             {
11545               info->angle = json_node_get_double (member);
11546               retval = TRUE;
11547             }
11548           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11549             retval = parse_rotation_array (actor,
11550                                            json_node_get_array (member),
11551                                            info);
11552           else
11553             retval = FALSE;
11554         }
11555       else if (json_object_has_member (object, "z-axis"))
11556         {
11557           member = json_object_get_member (object, "z-axis");
11558
11559           info->axis = CLUTTER_Z_AXIS;
11560
11561           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11562             {
11563               info->angle = json_node_get_double (member);
11564               retval = TRUE;
11565             }
11566           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11567             retval = parse_rotation_array (actor,
11568                                            json_node_get_array (member),
11569                                            info);
11570           else
11571             retval = FALSE;
11572         }
11573     }
11574
11575   return retval;
11576 }
11577
11578 static GSList *
11579 parse_actor_metas (ClutterScript *script,
11580                    ClutterActor  *actor,
11581                    JsonNode      *node)
11582 {
11583   GList *elements, *l;
11584   GSList *retval = NULL;
11585
11586   if (!JSON_NODE_HOLDS_ARRAY (node))
11587     return NULL;
11588
11589   elements = json_array_get_elements (json_node_get_array (node));
11590
11591   for (l = elements; l != NULL; l = l->next)
11592     {
11593       JsonNode *element = l->data;
11594       const gchar *id_ = _clutter_script_get_id_from_node (element);
11595       GObject *meta;
11596
11597       if (id_ == NULL || *id_ == '\0')
11598         continue;
11599
11600       meta = clutter_script_get_object (script, id_);
11601       if (meta == NULL)
11602         continue;
11603
11604       retval = g_slist_prepend (retval, meta);
11605     }
11606
11607   g_list_free (elements);
11608
11609   return g_slist_reverse (retval);
11610 }
11611
11612 static GSList *
11613 parse_behaviours (ClutterScript *script,
11614                   ClutterActor  *actor,
11615                   JsonNode      *node)
11616 {
11617   GList *elements, *l;
11618   GSList *retval = NULL;
11619
11620   if (!JSON_NODE_HOLDS_ARRAY (node))
11621     return NULL;
11622
11623   elements = json_array_get_elements (json_node_get_array (node));
11624
11625   for (l = elements; l != NULL; l = l->next)
11626     {
11627       JsonNode *element = l->data;
11628       const gchar *id_ = _clutter_script_get_id_from_node (element);
11629       GObject *behaviour;
11630
11631       if (id_ == NULL || *id_ == '\0')
11632         continue;
11633
11634       behaviour = clutter_script_get_object (script, id_);
11635       if (behaviour == NULL)
11636         continue;
11637
11638       retval = g_slist_prepend (retval, behaviour);
11639     }
11640
11641   g_list_free (elements);
11642
11643   return g_slist_reverse (retval);
11644 }
11645
11646 static gboolean
11647 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11648                                  ClutterScript     *script,
11649                                  GValue            *value,
11650                                  const gchar       *name,
11651                                  JsonNode          *node)
11652 {
11653   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11654   gboolean retval = FALSE;
11655
11656   if ((name[0] == 'x' && name[1] == '\0') ||
11657       (name[0] == 'y' && name[1] == '\0') ||
11658       (strcmp (name, "width") == 0) ||
11659       (strcmp (name, "height") == 0) ||
11660       (strcmp (name, "anchor_x") == 0) ||
11661       (strcmp (name, "anchor_y") == 0))
11662     {
11663       ParseDimension dimension;
11664       gfloat units;
11665
11666       if (name[0] == 'x')
11667         dimension = PARSE_X;
11668       else if (name[0] == 'y')
11669         dimension = PARSE_Y;
11670       else if (name[0] == 'w')
11671         dimension = PARSE_WIDTH;
11672       else if (name[0] == 'h')
11673         dimension = PARSE_HEIGHT;
11674       else if (name[0] == 'a' && name[7] == 'x')
11675         dimension = PARSE_ANCHOR_X;
11676       else if (name[0] == 'a' && name[7] == 'y')
11677         dimension = PARSE_ANCHOR_Y;
11678       else
11679         return FALSE;
11680
11681       units = parse_units (actor, dimension, node);
11682
11683       /* convert back to pixels: all properties are pixel-based */
11684       g_value_init (value, G_TYPE_FLOAT);
11685       g_value_set_float (value, units);
11686
11687       retval = TRUE;
11688     }
11689   else if (strcmp (name, "rotation") == 0)
11690     {
11691       RotationInfo *info;
11692
11693       info = g_slice_new0 (RotationInfo);
11694       retval = parse_rotation (actor, node, info);
11695
11696       if (retval)
11697         {
11698           g_value_init (value, G_TYPE_POINTER);
11699           g_value_set_pointer (value, info);
11700         }
11701       else
11702         g_slice_free (RotationInfo, info);
11703     }
11704   else if (strcmp (name, "behaviours") == 0)
11705     {
11706       GSList *l;
11707
11708 #ifdef CLUTTER_ENABLE_DEBUG
11709       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11710         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11711                                      "and it should not be used in newly "
11712                                      "written ClutterScript definitions.");
11713 #endif
11714
11715       l = parse_behaviours (script, actor, node);
11716
11717       g_value_init (value, G_TYPE_POINTER);
11718       g_value_set_pointer (value, l);
11719
11720       retval = TRUE;
11721     }
11722   else if (strcmp (name, "actions") == 0 ||
11723            strcmp (name, "constraints") == 0 ||
11724            strcmp (name, "effects") == 0)
11725     {
11726       GSList *l;
11727
11728       l = parse_actor_metas (script, actor, node);
11729
11730       g_value_init (value, G_TYPE_POINTER);
11731       g_value_set_pointer (value, l);
11732
11733       retval = TRUE;
11734     }
11735
11736   return retval;
11737 }
11738
11739 static void
11740 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11741                                    ClutterScript     *script,
11742                                    const gchar       *name,
11743                                    const GValue      *value)
11744 {
11745   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11746
11747 #ifdef CLUTTER_ENABLE_DEBUG
11748   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11749     {
11750       gchar *tmp = g_strdup_value_contents (value);
11751
11752       CLUTTER_NOTE (SCRIPT,
11753                     "in ClutterActor::set_custom_property('%s') = %s",
11754                     name,
11755                     tmp);
11756
11757       g_free (tmp);
11758     }
11759 #endif /* CLUTTER_ENABLE_DEBUG */
11760
11761   if (strcmp (name, "rotation") == 0)
11762     {
11763       RotationInfo *info;
11764
11765       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11766         return;
11767
11768       info = g_value_get_pointer (value);
11769
11770       clutter_actor_set_rotation (actor,
11771                                   info->axis, info->angle,
11772                                   info->center_x,
11773                                   info->center_y,
11774                                   info->center_z);
11775
11776       g_slice_free (RotationInfo, info);
11777
11778       return;
11779     }
11780
11781   if (strcmp (name, "behaviours") == 0)
11782     {
11783       GSList *behaviours, *l;
11784
11785       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11786         return;
11787
11788       behaviours = g_value_get_pointer (value);
11789       for (l = behaviours; l != NULL; l = l->next)
11790         {
11791           ClutterBehaviour *behaviour = l->data;
11792
11793           clutter_behaviour_apply (behaviour, actor);
11794         }
11795
11796       g_slist_free (behaviours);
11797
11798       return;
11799     }
11800
11801   if (strcmp (name, "actions") == 0 ||
11802       strcmp (name, "constraints") == 0 ||
11803       strcmp (name, "effects") == 0)
11804     {
11805       GSList *metas, *l;
11806
11807       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11808         return;
11809
11810       metas = g_value_get_pointer (value);
11811       for (l = metas; l != NULL; l = l->next)
11812         {
11813           if (name[0] == 'a')
11814             clutter_actor_add_action (actor, l->data);
11815
11816           if (name[0] == 'c')
11817             clutter_actor_add_constraint (actor, l->data);
11818
11819           if (name[0] == 'e')
11820             clutter_actor_add_effect (actor, l->data);
11821         }
11822
11823       g_slist_free (metas);
11824
11825       return;
11826     }
11827
11828   g_object_set_property (G_OBJECT (scriptable), name, value);
11829 }
11830
11831 static void
11832 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11833 {
11834   iface->parse_custom_node = clutter_actor_parse_custom_node;
11835   iface->set_custom_property = clutter_actor_set_custom_property;
11836 }
11837
11838 static ClutterActorMeta *
11839 get_meta_from_animation_property (ClutterActor  *actor,
11840                                   const gchar   *name,
11841                                   gchar        **name_p)
11842 {
11843   ClutterActorPrivate *priv = actor->priv;
11844   ClutterActorMeta *meta = NULL;
11845   gchar **tokens;
11846
11847   /* if this is not a special property, fall through */
11848   if (name[0] != '@')
11849     return NULL;
11850
11851   /* detect the properties named using the following spec:
11852    *
11853    *   @<section>.<meta-name>.<property-name>
11854    *
11855    * where <section> can be one of the following:
11856    *
11857    *   - actions
11858    *   - constraints
11859    *   - effects
11860    *
11861    * and <meta-name> is the name set on a specific ActorMeta
11862    */
11863
11864   tokens = g_strsplit (name + 1, ".", -1);
11865   if (tokens == NULL || g_strv_length (tokens) != 3)
11866     {
11867       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11868                     name + 1);
11869       g_strfreev (tokens);
11870       return NULL;
11871     }
11872
11873   if (strcmp (tokens[0], "actions") == 0)
11874     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11875
11876   if (strcmp (tokens[0], "constraints") == 0)
11877     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11878
11879   if (strcmp (tokens[0], "effects") == 0)
11880     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11881
11882   if (name_p != NULL)
11883     *name_p = g_strdup (tokens[2]);
11884
11885   CLUTTER_NOTE (ANIMATION,
11886                 "Looking for property '%s' of object '%s' in section '%s'",
11887                 tokens[2],
11888                 tokens[1],
11889                 tokens[0]);
11890
11891   g_strfreev (tokens);
11892
11893   return meta;
11894 }
11895
11896 static GParamSpec *
11897 clutter_actor_find_property (ClutterAnimatable *animatable,
11898                              const gchar       *property_name)
11899 {
11900   ClutterActorMeta *meta = NULL;
11901   GObjectClass *klass = NULL;
11902   GParamSpec *pspec = NULL;
11903   gchar *p_name = NULL;
11904
11905   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11906                                            property_name,
11907                                            &p_name);
11908
11909   if (meta != NULL)
11910     {
11911       klass = G_OBJECT_GET_CLASS (meta);
11912
11913       pspec = g_object_class_find_property (klass, p_name);
11914     }
11915   else
11916     {
11917       klass = G_OBJECT_GET_CLASS (animatable);
11918
11919       pspec = g_object_class_find_property (klass, property_name);
11920     }
11921
11922   g_free (p_name);
11923
11924   return pspec;
11925 }
11926
11927 static void
11928 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
11929                                  const gchar       *property_name,
11930                                  GValue            *initial)
11931 {
11932   ClutterActorMeta *meta = NULL;
11933   gchar *p_name = NULL;
11934
11935   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11936                                            property_name,
11937                                            &p_name);
11938
11939   if (meta != NULL)
11940     g_object_get_property (G_OBJECT (meta), p_name, initial);
11941   else
11942     g_object_get_property (G_OBJECT (animatable), property_name, initial);
11943
11944   g_free (p_name);
11945 }
11946
11947 static void
11948 clutter_actor_set_final_state (ClutterAnimatable *animatable,
11949                                const gchar       *property_name,
11950                                const GValue      *final)
11951 {
11952   ClutterActorMeta *meta = NULL;
11953   gchar *p_name = NULL;
11954
11955   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11956                                            property_name,
11957                                            &p_name);
11958   if (meta != NULL)
11959     g_object_set_property (G_OBJECT (meta), p_name, final);
11960   else
11961     g_object_set_property (G_OBJECT (animatable), property_name, final);
11962
11963   g_free (p_name);
11964 }
11965
11966 static void
11967 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
11968 {
11969   iface->find_property = clutter_actor_find_property;
11970   iface->get_initial_state = clutter_actor_get_initial_state;
11971   iface->set_final_state = clutter_actor_set_final_state;
11972 }
11973
11974 /**
11975  * clutter_actor_transform_stage_point:
11976  * @self: A #ClutterActor
11977  * @x: (in): x screen coordinate of the point to unproject
11978  * @y: (in): y screen coordinate of the point to unproject
11979  * @x_out: (out): return location for the unprojected x coordinance
11980  * @y_out: (out): return location for the unprojected y coordinance
11981  *
11982  * This function translates screen coordinates (@x, @y) to
11983  * coordinates relative to the actor. For example, it can be used to translate
11984  * screen events from global screen coordinates into actor-local coordinates.
11985  *
11986  * The conversion can fail, notably if the transform stack results in the
11987  * actor being projected on the screen as a mere line.
11988  *
11989  * The conversion should not be expected to be pixel-perfect due to the
11990  * nature of the operation. In general the error grows when the skewing
11991  * of the actor rectangle on screen increases.
11992  *
11993  * <note><para>This function can be computationally intensive.</para></note>
11994  *
11995  * <note><para>This function only works when the allocation is up-to-date,
11996  * i.e. inside of paint().</para></note>
11997  *
11998  * Return value: %TRUE if conversion was successful.
11999  *
12000  * Since: 0.6
12001  */
12002 gboolean
12003 clutter_actor_transform_stage_point (ClutterActor *self,
12004                                      gfloat        x,
12005                                      gfloat        y,
12006                                      gfloat       *x_out,
12007                                      gfloat       *y_out)
12008 {
12009   ClutterVertex v[4];
12010   float ST[3][3];
12011   float RQ[3][3];
12012   int du, dv, xi, yi;
12013   float px, py;
12014   float xf, yf, wf, det;
12015   ClutterActorPrivate *priv;
12016
12017   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12018
12019   priv = self->priv;
12020
12021   /* This implementation is based on the quad -> quad projection algorithm
12022    * described by Paul Heckbert in:
12023    *
12024    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12025    *
12026    * and the sample implementation at:
12027    *
12028    *   http://www.cs.cmu.edu/~ph/src/texfund/
12029    *
12030    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12031    * quad to rectangle only, which significantly simplifies things; the
12032    * function calls have been unrolled, and most of the math is done in fixed
12033    * point.
12034    */
12035
12036   clutter_actor_get_abs_allocation_vertices (self, v);
12037
12038   /* Keeping these as ints simplifies the multiplication (no significant
12039    * loss of precision here).
12040    */
12041   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12042   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12043
12044   if (!du || !dv)
12045     return FALSE;
12046
12047 #define UX2FP(x)        (x)
12048 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12049
12050   /* First, find mapping from unit uv square to xy quadrilateral; this
12051    * equivalent to the pmap_square_quad() functions in the sample
12052    * implementation, which we can simplify, since our target is always
12053    * a rectangle.
12054    */
12055   px = v[0].x - v[1].x + v[3].x - v[2].x;
12056   py = v[0].y - v[1].y + v[3].y - v[2].y;
12057
12058   if (!px && !py)
12059     {
12060       /* affine transform */
12061       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12062       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12063       RQ[2][0] = UX2FP (v[0].x);
12064       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12065       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12066       RQ[2][1] = UX2FP (v[0].y);
12067       RQ[0][2] = 0;
12068       RQ[1][2] = 0;
12069       RQ[2][2] = 1.0;
12070     }
12071   else
12072     {
12073       /* projective transform */
12074       double dx1, dx2, dy1, dy2, del;
12075
12076       dx1 = UX2FP (v[1].x - v[3].x);
12077       dx2 = UX2FP (v[2].x - v[3].x);
12078       dy1 = UX2FP (v[1].y - v[3].y);
12079       dy2 = UX2FP (v[2].y - v[3].y);
12080
12081       del = DET2FP (dx1, dx2, dy1, dy2);
12082       if (!del)
12083         return FALSE;
12084
12085       /*
12086        * The division here needs to be done in floating point for
12087        * precisions reasons.
12088        */
12089       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12090       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12091       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12092       RQ[2][2] = 1.0;
12093       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12094       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12095       RQ[2][0] = UX2FP (v[0].x);
12096       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12097       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12098       RQ[2][1] = UX2FP (v[0].y);
12099     }
12100
12101   /*
12102    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12103    * square. Since our rectangle is based at 0,0 we only need to scale.
12104    */
12105   RQ[0][0] /= du;
12106   RQ[1][0] /= dv;
12107   RQ[0][1] /= du;
12108   RQ[1][1] /= dv;
12109   RQ[0][2] /= du;
12110   RQ[1][2] /= dv;
12111
12112   /*
12113    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12114    * inverse of that.
12115    */
12116   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12117   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12118   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12119   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12120   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12121   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12122   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12123   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12124   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12125
12126   /*
12127    * Check the resulting matrix is OK.
12128    */
12129   det = (RQ[0][0] * ST[0][0])
12130       + (RQ[0][1] * ST[0][1])
12131       + (RQ[0][2] * ST[0][2]);
12132   if (!det)
12133     return FALSE;
12134
12135   /*
12136    * Now transform our point with the ST matrix; the notional w
12137    * coordinate is 1, hence the last part is simply added.
12138    */
12139   xi = (int) x;
12140   yi = (int) y;
12141
12142   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12143   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12144   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12145
12146   if (x_out)
12147     *x_out = xf / wf;
12148
12149   if (y_out)
12150     *y_out = yf / wf;
12151
12152 #undef UX2FP
12153 #undef DET2FP
12154
12155   return TRUE;
12156 }
12157
12158 /*
12159  * ClutterGeometry
12160  */
12161
12162 static ClutterGeometry*
12163 clutter_geometry_copy (const ClutterGeometry *geometry)
12164 {
12165   return g_slice_dup (ClutterGeometry, geometry);
12166 }
12167
12168 static void
12169 clutter_geometry_free (ClutterGeometry *geometry)
12170 {
12171   if (G_LIKELY (geometry != NULL))
12172     g_slice_free (ClutterGeometry, geometry);
12173 }
12174
12175 /**
12176  * clutter_geometry_union:
12177  * @geometry_a: a #ClutterGeometry
12178  * @geometry_b: another #ClutterGeometry
12179  * @result: (out): location to store the result
12180  *
12181  * Find the union of two rectangles represented as #ClutterGeometry.
12182  *
12183  * Since: 1.4
12184  */
12185 void
12186 clutter_geometry_union (const ClutterGeometry *geometry_a,
12187                         const ClutterGeometry *geometry_b,
12188                         ClutterGeometry       *result)
12189 {
12190   /* We don't try to handle rectangles that can't be represented
12191    * as a signed integer box */
12192   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12193   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12194   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12195                   geometry_b->x + (gint)geometry_b->width);
12196   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12197                   geometry_b->y + (gint)geometry_b->height);
12198   result->x = x_1;
12199   result->y = y_1;
12200   result->width = x_2 - x_1;
12201   result->height = y_2 - y_1;
12202 }
12203
12204 /**
12205  * clutter_geometry_intersects:
12206  * @geometry0: The first geometry to test
12207  * @geometry1: The second geometry to test
12208  *
12209  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12210  * they do else %FALSE.
12211  *
12212  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12213  * %FALSE.
12214  *
12215  * Since: 1.4
12216  */
12217 gboolean
12218 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12219                              const ClutterGeometry *geometry1)
12220 {
12221   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12222       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12223       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12224       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12225     return FALSE;
12226   else
12227     return TRUE;
12228 }
12229
12230 static gboolean
12231 clutter_geometry_progress (const GValue *a,
12232                            const GValue *b,
12233                            gdouble       progress,
12234                            GValue       *retval)
12235 {
12236   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12237   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12238   ClutterGeometry res = { 0, };
12239   gint a_width = a_geom->width;
12240   gint b_width = b_geom->width;
12241   gint a_height = a_geom->height;
12242   gint b_height = b_geom->height;
12243
12244   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12245   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12246
12247   res.width = a_width + (b_width - a_width) * progress;
12248   res.height = a_height + (b_height - a_height) * progress;
12249
12250   g_value_set_boxed (retval, &res);
12251
12252   return TRUE;
12253 }
12254
12255 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12256                                clutter_geometry_copy,
12257                                clutter_geometry_free,
12258                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12259
12260 /*
12261  * ClutterVertices
12262  */
12263
12264 /**
12265  * clutter_vertex_new:
12266  * @x: X coordinate
12267  * @y: Y coordinate
12268  * @z: Z coordinate
12269  *
12270  * Creates a new #ClutterVertex for the point in 3D space
12271  * identified by the 3 coordinates @x, @y, @z
12272  *
12273  * Return value: the newly allocate #ClutterVertex. Use
12274  *   clutter_vertex_free() to free the resources
12275  *
12276  * Since: 1.0
12277  */
12278 ClutterVertex *
12279 clutter_vertex_new (gfloat x,
12280                     gfloat y,
12281                     gfloat z)
12282 {
12283   ClutterVertex *vertex;
12284
12285   vertex = g_slice_new (ClutterVertex);
12286   vertex->x = x;
12287   vertex->y = y;
12288   vertex->z = z;
12289
12290   return vertex;
12291 }
12292
12293 /**
12294  * clutter_vertex_copy:
12295  * @vertex: a #ClutterVertex
12296  *
12297  * Copies @vertex
12298  *
12299  * Return value: a newly allocated copy of #ClutterVertex. Use
12300  *   clutter_vertex_free() to free the allocated resources
12301  *
12302  * Since: 1.0
12303  */
12304 ClutterVertex *
12305 clutter_vertex_copy (const ClutterVertex *vertex)
12306 {
12307   if (G_LIKELY (vertex != NULL))
12308     return g_slice_dup (ClutterVertex, vertex);
12309
12310   return NULL;
12311 }
12312
12313 /**
12314  * clutter_vertex_free:
12315  * @vertex: a #ClutterVertex
12316  *
12317  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12318  *
12319  * Since: 1.0
12320  */
12321 void
12322 clutter_vertex_free (ClutterVertex *vertex)
12323 {
12324   if (G_UNLIKELY (vertex != NULL))
12325     g_slice_free (ClutterVertex, vertex);
12326 }
12327
12328 /**
12329  * clutter_vertex_equal:
12330  * @vertex_a: a #ClutterVertex
12331  * @vertex_b: a #ClutterVertex
12332  *
12333  * Compares @vertex_a and @vertex_b for equality
12334  *
12335  * Return value: %TRUE if the passed #ClutterVertex are equal
12336  *
12337  * Since: 1.0
12338  */
12339 gboolean
12340 clutter_vertex_equal (const ClutterVertex *vertex_a,
12341                       const ClutterVertex *vertex_b)
12342 {
12343   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12344
12345   if (vertex_a == vertex_b)
12346     return TRUE;
12347
12348   return vertex_a->x == vertex_b->x &&
12349          vertex_a->y == vertex_b->y &&
12350          vertex_a->z == vertex_b->z;
12351 }
12352
12353 static gboolean
12354 clutter_vertex_progress (const GValue *a,
12355                          const GValue *b,
12356                          gdouble       progress,
12357                          GValue       *retval)
12358 {
12359   const ClutterVertex *av = g_value_get_boxed (a);
12360   const ClutterVertex *bv = g_value_get_boxed (b);
12361   ClutterVertex res = { 0, };
12362
12363   res.x = av->x + (bv->x - av->x) * progress;
12364   res.y = av->y + (bv->y - av->y) * progress;
12365   res.z = av->z + (bv->z - av->z) * progress;
12366
12367   g_value_set_boxed (retval, &res);
12368
12369   return TRUE;
12370 }
12371
12372 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12373                                clutter_vertex_copy,
12374                                clutter_vertex_free,
12375                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12376
12377 /**
12378  * clutter_actor_is_rotated:
12379  * @self: a #ClutterActor
12380  *
12381  * Checks whether any rotation is applied to the actor.
12382  *
12383  * Return value: %TRUE if the actor is rotated.
12384  *
12385  * Since: 0.6
12386  */
12387 gboolean
12388 clutter_actor_is_rotated (ClutterActor *self)
12389 {
12390   const ClutterTransformInfo *info;
12391
12392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12393
12394   info = _clutter_actor_get_transform_info_or_defaults (self);
12395
12396   if (info->rx_angle || info->ry_angle || info->rz_angle)
12397     return TRUE;
12398
12399   return FALSE;
12400 }
12401
12402 /**
12403  * clutter_actor_is_scaled:
12404  * @self: a #ClutterActor
12405  *
12406  * Checks whether the actor is scaled in either dimension.
12407  *
12408  * Return value: %TRUE if the actor is scaled.
12409  *
12410  * Since: 0.6
12411  */
12412 gboolean
12413 clutter_actor_is_scaled (ClutterActor *self)
12414 {
12415   const ClutterTransformInfo *info;
12416
12417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12418
12419   info = _clutter_actor_get_transform_info_or_defaults (self);
12420
12421   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12422     return TRUE;
12423
12424   return FALSE;
12425 }
12426
12427 ClutterActor *
12428 _clutter_actor_get_stage_internal (ClutterActor *actor)
12429 {
12430   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12431     actor = actor->priv->parent;
12432
12433   return actor;
12434 }
12435
12436 /**
12437  * clutter_actor_get_stage:
12438  * @actor: a #ClutterActor
12439  *
12440  * Retrieves the #ClutterStage where @actor is contained.
12441  *
12442  * Return value: (transfer none) (type Clutter.Stage): the stage
12443  *   containing the actor, or %NULL
12444  *
12445  * Since: 0.8
12446  */
12447 ClutterActor *
12448 clutter_actor_get_stage (ClutterActor *actor)
12449 {
12450   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12451
12452   return _clutter_actor_get_stage_internal (actor);
12453 }
12454
12455 /**
12456  * clutter_actor_allocate_available_size:
12457  * @self: a #ClutterActor
12458  * @x: the actor's X coordinate
12459  * @y: the actor's Y coordinate
12460  * @available_width: the maximum available width, or -1 to use the
12461  *   actor's natural width
12462  * @available_height: the maximum available height, or -1 to use the
12463  *   actor's natural height
12464  * @flags: flags controlling the allocation
12465  *
12466  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12467  * preferred size, but limiting it to the maximum available width
12468  * and height provided.
12469  *
12470  * This function will do the right thing when dealing with the
12471  * actor's request mode.
12472  *
12473  * The implementation of this function is equivalent to:
12474  *
12475  * |[
12476  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12477  *     {
12478  *       clutter_actor_get_preferred_width (self, available_height,
12479  *                                          &amp;min_width,
12480  *                                          &amp;natural_width);
12481  *       width = CLAMP (natural_width, min_width, available_width);
12482  *
12483  *       clutter_actor_get_preferred_height (self, width,
12484  *                                           &amp;min_height,
12485  *                                           &amp;natural_height);
12486  *       height = CLAMP (natural_height, min_height, available_height);
12487  *     }
12488  *   else
12489  *     {
12490  *       clutter_actor_get_preferred_height (self, available_width,
12491  *                                           &amp;min_height,
12492  *                                           &amp;natural_height);
12493  *       height = CLAMP (natural_height, min_height, available_height);
12494  *
12495  *       clutter_actor_get_preferred_width (self, height,
12496  *                                          &amp;min_width,
12497  *                                          &amp;natural_width);
12498  *       width = CLAMP (natural_width, min_width, available_width);
12499  *     }
12500  *
12501  *   box.x1 = x; box.y1 = y;
12502  *   box.x2 = box.x1 + available_width;
12503  *   box.y2 = box.y1 + available_height;
12504  *   clutter_actor_allocate (self, &amp;box, flags);
12505  * ]|
12506  *
12507  * This function can be used by fluid layout managers to allocate
12508  * an actor's preferred size without making it bigger than the area
12509  * available for the container.
12510  *
12511  * Since: 1.0
12512  */
12513 void
12514 clutter_actor_allocate_available_size (ClutterActor           *self,
12515                                        gfloat                  x,
12516                                        gfloat                  y,
12517                                        gfloat                  available_width,
12518                                        gfloat                  available_height,
12519                                        ClutterAllocationFlags  flags)
12520 {
12521   ClutterActorPrivate *priv;
12522   gfloat width, height;
12523   gfloat min_width, min_height;
12524   gfloat natural_width, natural_height;
12525   ClutterActorBox box;
12526
12527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12528
12529   priv = self->priv;
12530
12531   width = height = 0.0;
12532
12533   switch (priv->request_mode)
12534     {
12535     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12536       clutter_actor_get_preferred_width (self, available_height,
12537                                          &min_width,
12538                                          &natural_width);
12539       width  = CLAMP (natural_width, min_width, available_width);
12540
12541       clutter_actor_get_preferred_height (self, width,
12542                                           &min_height,
12543                                           &natural_height);
12544       height = CLAMP (natural_height, min_height, available_height);
12545       break;
12546
12547     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12548       clutter_actor_get_preferred_height (self, available_width,
12549                                           &min_height,
12550                                           &natural_height);
12551       height = CLAMP (natural_height, min_height, available_height);
12552
12553       clutter_actor_get_preferred_width (self, height,
12554                                          &min_width,
12555                                          &natural_width);
12556       width  = CLAMP (natural_width, min_width, available_width);
12557       break;
12558     }
12559
12560
12561   box.x1 = x;
12562   box.y1 = y;
12563   box.x2 = box.x1 + width;
12564   box.y2 = box.y1 + height;
12565   clutter_actor_allocate (self, &box, flags);
12566 }
12567
12568 /**
12569  * clutter_actor_allocate_preferred_size:
12570  * @self: a #ClutterActor
12571  * @flags: flags controlling the allocation
12572  *
12573  * Allocates the natural size of @self.
12574  *
12575  * This function is a utility call for #ClutterActor implementations
12576  * that allocates the actor's preferred natural size. It can be used
12577  * by fixed layout managers (like #ClutterGroup or so called
12578  * 'composite actors') inside the ClutterActor::allocate
12579  * implementation to give each child exactly how much space it
12580  * requires.
12581  *
12582  * This function is not meant to be used by applications. It is also
12583  * not meant to be used outside the implementation of the
12584  * ClutterActor::allocate virtual function.
12585  *
12586  * Since: 0.8
12587  */
12588 void
12589 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12590                                        ClutterAllocationFlags  flags)
12591 {
12592   gfloat actor_x, actor_y;
12593   gfloat natural_width, natural_height;
12594   ClutterActorBox actor_box;
12595
12596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12597
12598   actor_x = clutter_actor_get_x (self);
12599   actor_y = clutter_actor_get_y (self);
12600
12601   clutter_actor_get_preferred_size (self,
12602                                     NULL, NULL,
12603                                     &natural_width,
12604                                     &natural_height);
12605
12606   actor_box.x1 = actor_x;
12607   actor_box.y1 = actor_y;
12608   actor_box.x2 = actor_box.x1 + natural_width;
12609   actor_box.y2 = actor_box.y1 + natural_height;
12610
12611   clutter_actor_allocate (self, &actor_box, flags);
12612 }
12613
12614 /**
12615  * clutter_actor_allocate_align_fill:
12616  * @self: a #ClutterActor
12617  * @box: a #ClutterActorBox, containing the available width and height
12618  * @x_align: the horizontal alignment, between 0 and 1
12619  * @y_align: the vertical alignment, between 0 and 1
12620  * @x_fill: whether the actor should fill horizontally
12621  * @y_fill: whether the actor should fill vertically
12622  * @flags: allocation flags to be passed to clutter_actor_allocate()
12623  *
12624  * Allocates @self by taking into consideration the available allocation
12625  * area; an alignment factor on either axis; and whether the actor should
12626  * fill the allocation on either axis.
12627  *
12628  * The @box should contain the available allocation width and height;
12629  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12630  * allocation will be offset by their value.
12631  *
12632  * This function takes into consideration the geometry request specified by
12633  * the #ClutterActor:request-mode property, and the text direction.
12634  *
12635  * This function is useful for fluid layout managers, like #ClutterBinLayout
12636  * or #ClutterTableLayout
12637  *
12638  * Since: 1.4
12639  */
12640 void
12641 clutter_actor_allocate_align_fill (ClutterActor           *self,
12642                                    const ClutterActorBox  *box,
12643                                    gdouble                 x_align,
12644                                    gdouble                 y_align,
12645                                    gboolean                x_fill,
12646                                    gboolean                y_fill,
12647                                    ClutterAllocationFlags  flags)
12648 {
12649   ClutterActorPrivate *priv;
12650   ClutterActorBox allocation = { 0, };
12651   gfloat x_offset, y_offset;
12652   gfloat available_width, available_height;
12653   gfloat child_width, child_height;
12654
12655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12656   g_return_if_fail (box != NULL);
12657   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12658   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12659
12660   priv = self->priv;
12661
12662   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12663   clutter_actor_box_get_size (box, &available_width, &available_height);
12664
12665   if (available_width < 0)
12666     available_width = 0;
12667
12668   if (available_height < 0)
12669     available_height = 0;
12670
12671   if (x_fill)
12672     {
12673       allocation.x1 = x_offset;
12674       allocation.x2 = allocation.x1 + available_width;
12675     }
12676
12677   if (y_fill)
12678     {
12679       allocation.y1 = y_offset;
12680       allocation.y2 = allocation.y1 + available_height;
12681     }
12682
12683   /* if we are filling horizontally and vertically then we're done */
12684   if (x_fill && y_fill)
12685     goto out;
12686
12687   child_width = child_height = 0.0f;
12688
12689   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12690     {
12691       gfloat min_width, natural_width;
12692       gfloat min_height, natural_height;
12693
12694       clutter_actor_get_preferred_width (self, available_height,
12695                                          &min_width,
12696                                          &natural_width);
12697
12698       child_width = CLAMP (natural_width, min_width, available_width);
12699
12700       if (!y_fill)
12701         {
12702           clutter_actor_get_preferred_height (self, child_width,
12703                                               &min_height,
12704                                               &natural_height);
12705
12706           child_height = CLAMP (natural_height, min_height, available_height);
12707         }
12708     }
12709   else
12710     {
12711       gfloat min_width, natural_width;
12712       gfloat min_height, natural_height;
12713
12714       clutter_actor_get_preferred_height (self, available_width,
12715                                           &min_height,
12716                                           &natural_height);
12717
12718       child_height = CLAMP (natural_height, min_height, available_height);
12719
12720       if (!x_fill)
12721         {
12722           clutter_actor_get_preferred_width (self, child_height,
12723                                              &min_width,
12724                                              &natural_width);
12725
12726           child_width = CLAMP (natural_width, min_width, available_width);
12727         }
12728     }
12729
12730   /* invert the horizontal alignment for RTL languages */
12731   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12732     x_align = 1.0 - x_align;
12733
12734   if (!x_fill)
12735     {
12736       allocation.x1 = x_offset
12737                     + ((available_width - child_width) * x_align);
12738       allocation.x2 = allocation.x1 + child_width;
12739     }
12740
12741   if (!y_fill)
12742     {
12743       allocation.y1 = y_offset
12744                     + ((available_height - child_height) * y_align);
12745       allocation.y2 = allocation.y1 + child_height;
12746     }
12747
12748 out:
12749   clutter_actor_box_clamp_to_pixel (&allocation);
12750   clutter_actor_allocate (self, &allocation, flags);
12751 }
12752
12753 /**
12754  * clutter_actor_grab_key_focus:
12755  * @self: a #ClutterActor
12756  *
12757  * Sets the key focus of the #ClutterStage including @self
12758  * to this #ClutterActor.
12759  *
12760  * Since: 1.0
12761  */
12762 void
12763 clutter_actor_grab_key_focus (ClutterActor *self)
12764 {
12765   ClutterActor *stage;
12766
12767   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12768
12769   stage = _clutter_actor_get_stage_internal (self);
12770   if (stage != NULL)
12771     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12772 }
12773
12774 /**
12775  * clutter_actor_get_pango_context:
12776  * @self: a #ClutterActor
12777  *
12778  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12779  * is already configured using the appropriate font map, resolution
12780  * and font options.
12781  *
12782  * Unlike clutter_actor_create_pango_context(), this context is owend
12783  * by the #ClutterActor and it will be updated each time the options
12784  * stored by the #ClutterBackend change.
12785  *
12786  * You can use the returned #PangoContext to create a #PangoLayout
12787  * and render text using cogl_pango_render_layout() to reuse the
12788  * glyphs cache also used by Clutter.
12789  *
12790  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12791  *   The returned #PangoContext is owned by the actor and should not be
12792  *   unreferenced by the application code
12793  *
12794  * Since: 1.0
12795  */
12796 PangoContext *
12797 clutter_actor_get_pango_context (ClutterActor *self)
12798 {
12799   ClutterActorPrivate *priv;
12800
12801   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12802
12803   priv = self->priv;
12804
12805   if (priv->pango_context != NULL)
12806     return priv->pango_context;
12807
12808   priv->pango_context = _clutter_context_get_pango_context ();
12809   g_object_ref (priv->pango_context);
12810
12811   return priv->pango_context;
12812 }
12813
12814 /**
12815  * clutter_actor_create_pango_context:
12816  * @self: a #ClutterActor
12817  *
12818  * Creates a #PangoContext for the given actor. The #PangoContext
12819  * is already configured using the appropriate font map, resolution
12820  * and font options.
12821  *
12822  * See also clutter_actor_get_pango_context().
12823  *
12824  * Return value: (transfer full): the newly created #PangoContext.
12825  *   Use g_object_unref() on the returned value to deallocate its
12826  *   resources
12827  *
12828  * Since: 1.0
12829  */
12830 PangoContext *
12831 clutter_actor_create_pango_context (ClutterActor *self)
12832 {
12833   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12834
12835   return _clutter_context_create_pango_context ();
12836 }
12837
12838 /**
12839  * clutter_actor_create_pango_layout:
12840  * @self: a #ClutterActor
12841  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12842  *
12843  * Creates a new #PangoLayout from the same #PangoContext used
12844  * by the #ClutterActor. The #PangoLayout is already configured
12845  * with the font map, resolution and font options, and the
12846  * given @text.
12847  *
12848  * If you want to keep around a #PangoLayout created by this
12849  * function you will have to connect to the #ClutterBackend::font-changed
12850  * and #ClutterBackend::resolution-changed signals, and call
12851  * pango_layout_context_changed() in response to them.
12852  *
12853  * Return value: (transfer full): the newly created #PangoLayout.
12854  *   Use g_object_unref() when done
12855  *
12856  * Since: 1.0
12857  */
12858 PangoLayout *
12859 clutter_actor_create_pango_layout (ClutterActor *self,
12860                                    const gchar  *text)
12861 {
12862   PangoContext *context;
12863   PangoLayout *layout;
12864
12865   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12866
12867   context = clutter_actor_get_pango_context (self);
12868   layout = pango_layout_new (context);
12869
12870   if (text)
12871     pango_layout_set_text (layout, text, -1);
12872
12873   return layout;
12874 }
12875
12876 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12877  * ClutterOffscreenEffect.
12878  */
12879 void
12880 _clutter_actor_set_opacity_override (ClutterActor *self,
12881                                      gint          opacity)
12882 {
12883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12884
12885   self->priv->opacity_override = opacity;
12886 }
12887
12888 gint
12889 _clutter_actor_get_opacity_override (ClutterActor *self)
12890 {
12891   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12892
12893   return self->priv->opacity_override;
12894 }
12895
12896 /* Allows you to disable applying the actors model view transform during
12897  * a paint. Used by ClutterClone. */
12898 void
12899 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12900                                                 gboolean      enable)
12901 {
12902   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12903
12904   self->priv->enable_model_view_transform = enable;
12905 }
12906
12907 void
12908 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12909                                           gboolean      enable)
12910 {
12911   ClutterActorPrivate *priv;
12912
12913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12914
12915   priv = self->priv;
12916
12917   priv->enable_paint_unmapped = enable;
12918
12919   if (priv->enable_paint_unmapped)
12920     {
12921       /* Make sure that the parents of the widget are realized first;
12922        * otherwise checks in clutter_actor_update_map_state() will
12923        * fail.
12924        */
12925       clutter_actor_realize (self);
12926
12927       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
12928     }
12929   else
12930     {
12931       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
12932     }
12933 }
12934
12935 static void
12936 clutter_anchor_coord_get_units (ClutterActor      *self,
12937                                 const AnchorCoord *coord,
12938                                 gfloat            *x,
12939                                 gfloat            *y,
12940                                 gfloat            *z)
12941 {
12942   if (coord->is_fractional)
12943     {
12944       gfloat actor_width, actor_height;
12945
12946       clutter_actor_get_size (self, &actor_width, &actor_height);
12947
12948       if (x)
12949         *x = actor_width * coord->v.fraction.x;
12950
12951       if (y)
12952         *y = actor_height * coord->v.fraction.y;
12953
12954       if (z)
12955         *z = 0;
12956     }
12957   else
12958     {
12959       if (x)
12960         *x = coord->v.units.x;
12961
12962       if (y)
12963         *y = coord->v.units.y;
12964
12965       if (z)
12966         *z = coord->v.units.z;
12967     }
12968 }
12969
12970 static void
12971 clutter_anchor_coord_set_units (AnchorCoord *coord,
12972                                 gfloat       x,
12973                                 gfloat       y,
12974                                 gfloat       z)
12975 {
12976   coord->is_fractional = FALSE;
12977   coord->v.units.x = x;
12978   coord->v.units.y = y;
12979   coord->v.units.z = z;
12980 }
12981
12982 static ClutterGravity
12983 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
12984 {
12985   if (coord->is_fractional)
12986     {
12987       if (coord->v.fraction.x == 0.0)
12988         {
12989           if (coord->v.fraction.y == 0.0)
12990             return CLUTTER_GRAVITY_NORTH_WEST;
12991           else if (coord->v.fraction.y == 0.5)
12992             return CLUTTER_GRAVITY_WEST;
12993           else if (coord->v.fraction.y == 1.0)
12994             return CLUTTER_GRAVITY_SOUTH_WEST;
12995           else
12996             return CLUTTER_GRAVITY_NONE;
12997         }
12998       else if (coord->v.fraction.x == 0.5)
12999         {
13000           if (coord->v.fraction.y == 0.0)
13001             return CLUTTER_GRAVITY_NORTH;
13002           else if (coord->v.fraction.y == 0.5)
13003             return CLUTTER_GRAVITY_CENTER;
13004           else if (coord->v.fraction.y == 1.0)
13005             return CLUTTER_GRAVITY_SOUTH;
13006           else
13007             return CLUTTER_GRAVITY_NONE;
13008         }
13009       else if (coord->v.fraction.x == 1.0)
13010         {
13011           if (coord->v.fraction.y == 0.0)
13012             return CLUTTER_GRAVITY_NORTH_EAST;
13013           else if (coord->v.fraction.y == 0.5)
13014             return CLUTTER_GRAVITY_EAST;
13015           else if (coord->v.fraction.y == 1.0)
13016             return CLUTTER_GRAVITY_SOUTH_EAST;
13017           else
13018             return CLUTTER_GRAVITY_NONE;
13019         }
13020       else
13021         return CLUTTER_GRAVITY_NONE;
13022     }
13023   else
13024     return CLUTTER_GRAVITY_NONE;
13025 }
13026
13027 static void
13028 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13029                                   ClutterGravity  gravity)
13030 {
13031   switch (gravity)
13032     {
13033     case CLUTTER_GRAVITY_NORTH:
13034       coord->v.fraction.x = 0.5;
13035       coord->v.fraction.y = 0.0;
13036       break;
13037
13038     case CLUTTER_GRAVITY_NORTH_EAST:
13039       coord->v.fraction.x = 1.0;
13040       coord->v.fraction.y = 0.0;
13041       break;
13042
13043     case CLUTTER_GRAVITY_EAST:
13044       coord->v.fraction.x = 1.0;
13045       coord->v.fraction.y = 0.5;
13046       break;
13047
13048     case CLUTTER_GRAVITY_SOUTH_EAST:
13049       coord->v.fraction.x = 1.0;
13050       coord->v.fraction.y = 1.0;
13051       break;
13052
13053     case CLUTTER_GRAVITY_SOUTH:
13054       coord->v.fraction.x = 0.5;
13055       coord->v.fraction.y = 1.0;
13056       break;
13057
13058     case CLUTTER_GRAVITY_SOUTH_WEST:
13059       coord->v.fraction.x = 0.0;
13060       coord->v.fraction.y = 1.0;
13061       break;
13062
13063     case CLUTTER_GRAVITY_WEST:
13064       coord->v.fraction.x = 0.0;
13065       coord->v.fraction.y = 0.5;
13066       break;
13067
13068     case CLUTTER_GRAVITY_NORTH_WEST:
13069       coord->v.fraction.x = 0.0;
13070       coord->v.fraction.y = 0.0;
13071       break;
13072
13073     case CLUTTER_GRAVITY_CENTER:
13074       coord->v.fraction.x = 0.5;
13075       coord->v.fraction.y = 0.5;
13076       break;
13077
13078     default:
13079       coord->v.fraction.x = 0.0;
13080       coord->v.fraction.y = 0.0;
13081       break;
13082     }
13083
13084   coord->is_fractional = TRUE;
13085 }
13086
13087 static gboolean
13088 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13089 {
13090   if (coord->is_fractional)
13091     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13092   else
13093     return (coord->v.units.x == 0.0
13094             && coord->v.units.y == 0.0
13095             && coord->v.units.z == 0.0);
13096 }
13097
13098 /**
13099  * clutter_actor_get_flags:
13100  * @self: a #ClutterActor
13101  *
13102  * Retrieves the flags set on @self
13103  *
13104  * Return value: a bitwise or of #ClutterActorFlags or 0
13105  *
13106  * Since: 1.0
13107  */
13108 ClutterActorFlags
13109 clutter_actor_get_flags (ClutterActor *self)
13110 {
13111   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13112
13113   return self->flags;
13114 }
13115
13116 /**
13117  * clutter_actor_set_flags:
13118  * @self: a #ClutterActor
13119  * @flags: the flags to set
13120  *
13121  * Sets @flags on @self
13122  *
13123  * This function will emit notifications for the changed properties
13124  *
13125  * Since: 1.0
13126  */
13127 void
13128 clutter_actor_set_flags (ClutterActor      *self,
13129                          ClutterActorFlags  flags)
13130 {
13131   ClutterActorFlags old_flags;
13132   GObject *obj;
13133   gboolean was_reactive_set, reactive_set;
13134   gboolean was_realized_set, realized_set;
13135   gboolean was_mapped_set, mapped_set;
13136   gboolean was_visible_set, visible_set;
13137
13138   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13139
13140   if (self->flags == flags)
13141     return;
13142
13143   obj = G_OBJECT (self);
13144   g_object_ref (obj);
13145   g_object_freeze_notify (obj);
13146
13147   old_flags = self->flags;
13148
13149   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13150   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13151   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13152   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13153
13154   self->flags |= flags;
13155
13156   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13157   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13158   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13159   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13160
13161   if (reactive_set != was_reactive_set)
13162     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13163
13164   if (realized_set != was_realized_set)
13165     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13166
13167   if (mapped_set != was_mapped_set)
13168     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13169
13170   if (visible_set != was_visible_set)
13171     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13172
13173   g_object_thaw_notify (obj);
13174   g_object_unref (obj);
13175 }
13176
13177 /**
13178  * clutter_actor_unset_flags:
13179  * @self: a #ClutterActor
13180  * @flags: the flags to unset
13181  *
13182  * Unsets @flags on @self
13183  *
13184  * This function will emit notifications for the changed properties
13185  *
13186  * Since: 1.0
13187  */
13188 void
13189 clutter_actor_unset_flags (ClutterActor      *self,
13190                            ClutterActorFlags  flags)
13191 {
13192   ClutterActorFlags old_flags;
13193   GObject *obj;
13194   gboolean was_reactive_set, reactive_set;
13195   gboolean was_realized_set, realized_set;
13196   gboolean was_mapped_set, mapped_set;
13197   gboolean was_visible_set, visible_set;
13198
13199   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13200
13201   obj = G_OBJECT (self);
13202   g_object_freeze_notify (obj);
13203
13204   old_flags = self->flags;
13205
13206   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13207   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13208   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13209   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13210
13211   self->flags &= ~flags;
13212
13213   if (self->flags == old_flags)
13214     return;
13215
13216   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13217   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13218   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13219   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13220
13221   if (reactive_set != was_reactive_set)
13222     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13223
13224   if (realized_set != was_realized_set)
13225     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13226
13227   if (mapped_set != was_mapped_set)
13228     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13229
13230   if (visible_set != was_visible_set)
13231     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13232
13233   g_object_thaw_notify (obj);
13234 }
13235
13236 /**
13237  * clutter_actor_get_transformation_matrix:
13238  * @self: a #ClutterActor
13239  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13240  *
13241  * Retrieves the transformations applied to @self relative to its
13242  * parent.
13243  *
13244  * Since: 1.0
13245  */
13246 void
13247 clutter_actor_get_transformation_matrix (ClutterActor *self,
13248                                          CoglMatrix   *matrix)
13249 {
13250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13251
13252   cogl_matrix_init_identity (matrix);
13253
13254   _clutter_actor_apply_modelview_transform (self, matrix);
13255 }
13256
13257 void
13258 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13259                                    gboolean      is_in_clone_paint)
13260 {
13261   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13262   self->priv->in_clone_paint = is_in_clone_paint;
13263 }
13264
13265 /**
13266  * clutter_actor_is_in_clone_paint:
13267  * @self: a #ClutterActor
13268  *
13269  * Checks whether @self is being currently painted by a #ClutterClone
13270  *
13271  * This function is useful only inside the ::paint virtual function
13272  * implementations or within handlers for the #ClutterActor::paint
13273  * signal
13274  *
13275  * This function should not be used by applications
13276  *
13277  * Return value: %TRUE if the #ClutterActor is currently being painted
13278  *   by a #ClutterClone, and %FALSE otherwise
13279  *
13280  * Since: 1.0
13281  */
13282 gboolean
13283 clutter_actor_is_in_clone_paint (ClutterActor *self)
13284 {
13285   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13286
13287   return self->priv->in_clone_paint;
13288 }
13289
13290 static gboolean
13291 set_direction_recursive (ClutterActor *actor,
13292                          gpointer      user_data)
13293 {
13294   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13295
13296   clutter_actor_set_text_direction (actor, text_dir);
13297
13298   return TRUE;
13299 }
13300
13301 /**
13302  * clutter_actor_set_text_direction:
13303  * @self: a #ClutterActor
13304  * @text_dir: the text direction for @self
13305  *
13306  * Sets the #ClutterTextDirection for an actor
13307  *
13308  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13309  *
13310  * If @self implements #ClutterContainer then this function will recurse
13311  * inside all the children of @self (including the internal ones).
13312  *
13313  * Composite actors not implementing #ClutterContainer, or actors requiring
13314  * special handling when the text direction changes, should connect to
13315  * the #GObject::notify signal for the #ClutterActor:text-direction property
13316  *
13317  * Since: 1.2
13318  */
13319 void
13320 clutter_actor_set_text_direction (ClutterActor         *self,
13321                                   ClutterTextDirection  text_dir)
13322 {
13323   ClutterActorPrivate *priv;
13324
13325   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13326   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13327
13328   priv = self->priv;
13329
13330   if (priv->text_direction != text_dir)
13331     {
13332       priv->text_direction = text_dir;
13333
13334       /* we need to emit the notify::text-direction first, so that
13335        * the sub-classes can catch that and do specific handling of
13336        * the text direction; see clutter_text_direction_changed_cb()
13337        * inside clutter-text.c
13338        */
13339       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13340
13341       _clutter_actor_foreach_child (self, set_direction_recursive,
13342                                     GINT_TO_POINTER (text_dir));
13343
13344       clutter_actor_queue_relayout (self);
13345     }
13346 }
13347
13348 void
13349 _clutter_actor_set_has_pointer (ClutterActor *self,
13350                                 gboolean      has_pointer)
13351 {
13352   ClutterActorPrivate *priv = self->priv;
13353
13354   if (priv->has_pointer != has_pointer)
13355     {
13356       priv->has_pointer = has_pointer;
13357
13358       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13359     }
13360 }
13361
13362 /**
13363  * clutter_actor_get_text_direction:
13364  * @self: a #ClutterActor
13365  *
13366  * Retrieves the value set using clutter_actor_set_text_direction()
13367  *
13368  * If no text direction has been previously set, the default text
13369  * direction, as returned by clutter_get_default_text_direction(), will
13370  * be returned instead
13371  *
13372  * Return value: the #ClutterTextDirection for the actor
13373  *
13374  * Since: 1.2
13375  */
13376 ClutterTextDirection
13377 clutter_actor_get_text_direction (ClutterActor *self)
13378 {
13379   ClutterActorPrivate *priv;
13380
13381   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13382                         CLUTTER_TEXT_DIRECTION_LTR);
13383
13384   priv = self->priv;
13385
13386   /* if no direction has been set yet use the default */
13387   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13388     priv->text_direction = clutter_get_default_text_direction ();
13389
13390   return priv->text_direction;
13391 }
13392
13393 /**
13394  * clutter_actor_push_internal:
13395  * @self: a #ClutterActor
13396  *
13397  * Should be used by actors implementing the #ClutterContainer and with
13398  * internal children added through clutter_actor_set_parent(), for instance:
13399  *
13400  * |[
13401  *   static void
13402  *   my_actor_init (MyActor *self)
13403  *   {
13404  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13405  *
13406  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13407  *
13408  *     /&ast; calling clutter_actor_set_parent() now will result in
13409  *      &ast; the internal flag being set on a child of MyActor
13410  *      &ast;/
13411  *
13412  *     /&ast; internal child - a background texture &ast;/
13413  *     self->priv->background_tex = clutter_texture_new ();
13414  *     clutter_actor_set_parent (self->priv->background_tex,
13415  *                               CLUTTER_ACTOR (self));
13416  *
13417  *     /&ast; internal child - a label &ast;/
13418  *     self->priv->label = clutter_text_new ();
13419  *     clutter_actor_set_parent (self->priv->label,
13420  *                               CLUTTER_ACTOR (self));
13421  *
13422  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13423  *
13424  *     /&ast; calling clutter_actor_set_parent() now will not result in
13425  *      &ast; the internal flag being set on a child of MyActor
13426  *      &ast;/
13427  *   }
13428  * ]|
13429  *
13430  * This function will be used by Clutter to toggle an "internal child"
13431  * flag whenever clutter_actor_set_parent() is called; internal children
13432  * are handled differently by Clutter, specifically when destroying their
13433  * parent.
13434  *
13435  * Call clutter_actor_pop_internal() when you finished adding internal
13436  * children.
13437  *
13438  * Nested calls to clutter_actor_push_internal() are allowed, but each
13439  * one must by followed by a clutter_actor_pop_internal() call.
13440  *
13441  * Since: 1.2
13442  *
13443  * Deprecated: 1.10: All children of an actor are accessible through
13444  *   the #ClutterActor API, and #ClutterActor implements the
13445  *   #ClutterContainer interface, so this function is only useful
13446  *   for legacy containers overriding the default implementation.
13447  */
13448 void
13449 clutter_actor_push_internal (ClutterActor *self)
13450 {
13451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13452
13453   self->priv->internal_child += 1;
13454 }
13455
13456 /**
13457  * clutter_actor_pop_internal:
13458  * @self: a #ClutterActor
13459  *
13460  * Disables the effects of clutter_actor_push_internal().
13461  *
13462  * Since: 1.2
13463  *
13464  * Deprecated: 1.10: All children of an actor are accessible through
13465  *   the #ClutterActor API. This function is only useful for legacy
13466  *   containers overriding the default implementation of the
13467  *   #ClutterContainer interface.
13468  */
13469 void
13470 clutter_actor_pop_internal (ClutterActor *self)
13471 {
13472   ClutterActorPrivate *priv;
13473
13474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13475
13476   priv = self->priv;
13477
13478   if (priv->internal_child == 0)
13479     {
13480       g_warning ("Mismatched %s: you need to call "
13481                  "clutter_actor_push_composite() at least once before "
13482                  "calling this function", G_STRFUNC);
13483       return;
13484     }
13485
13486   priv->internal_child -= 1;
13487 }
13488
13489 /**
13490  * clutter_actor_has_pointer:
13491  * @self: a #ClutterActor
13492  *
13493  * Checks whether an actor contains the pointer of a
13494  * #ClutterInputDevice
13495  *
13496  * Return value: %TRUE if the actor contains the pointer, and
13497  *   %FALSE otherwise
13498  *
13499  * Since: 1.2
13500  */
13501 gboolean
13502 clutter_actor_has_pointer (ClutterActor *self)
13503 {
13504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13505
13506   return self->priv->has_pointer;
13507 }
13508
13509 /* XXX: This is a workaround for not being able to break the ABI of
13510  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13511  * clutter_actor_queue_clipped_redraw() for details.
13512  */
13513 ClutterPaintVolume *
13514 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13515 {
13516   return g_object_get_data (G_OBJECT (self),
13517                             "-clutter-actor-queue-redraw-clip");
13518 }
13519
13520 void
13521 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13522                                       ClutterPaintVolume *clip)
13523 {
13524   g_object_set_data (G_OBJECT (self),
13525                      "-clutter-actor-queue-redraw-clip",
13526                      clip);
13527 }
13528
13529 /**
13530  * clutter_actor_has_allocation:
13531  * @self: a #ClutterActor
13532  *
13533  * Checks if the actor has an up-to-date allocation assigned to
13534  * it. This means that the actor should have an allocation: it's
13535  * visible and has a parent. It also means that there is no
13536  * outstanding relayout request in progress for the actor or its
13537  * children (There might be other outstanding layout requests in
13538  * progress that will cause the actor to get a new allocation
13539  * when the stage is laid out, however).
13540  *
13541  * If this function returns %FALSE, then the actor will normally
13542  * be allocated before it is next drawn on the screen.
13543  *
13544  * Return value: %TRUE if the actor has an up-to-date allocation
13545  *
13546  * Since: 1.4
13547  */
13548 gboolean
13549 clutter_actor_has_allocation (ClutterActor *self)
13550 {
13551   ClutterActorPrivate *priv;
13552
13553   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13554
13555   priv = self->priv;
13556
13557   return priv->parent != NULL &&
13558          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13559          !priv->needs_allocation;
13560 }
13561
13562 /**
13563  * clutter_actor_add_action:
13564  * @self: a #ClutterActor
13565  * @action: a #ClutterAction
13566  *
13567  * Adds @action to the list of actions applied to @self
13568  *
13569  * A #ClutterAction can only belong to one actor at a time
13570  *
13571  * The #ClutterActor will hold a reference on @action until either
13572  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13573  * is called
13574  *
13575  * Since: 1.4
13576  */
13577 void
13578 clutter_actor_add_action (ClutterActor  *self,
13579                           ClutterAction *action)
13580 {
13581   ClutterActorPrivate *priv;
13582
13583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13584   g_return_if_fail (CLUTTER_IS_ACTION (action));
13585
13586   priv = self->priv;
13587
13588   if (priv->actions == NULL)
13589     {
13590       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13591       priv->actions->actor = self;
13592     }
13593
13594   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13595
13596   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13597 }
13598
13599 /**
13600  * clutter_actor_add_action_with_name:
13601  * @self: a #ClutterActor
13602  * @name: the name to set on the action
13603  * @action: a #ClutterAction
13604  *
13605  * A convenience function for setting the name of a #ClutterAction
13606  * while adding it to the list of actions applied to @self
13607  *
13608  * This function is the logical equivalent of:
13609  *
13610  * |[
13611  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13612  *   clutter_actor_add_action (self, action);
13613  * ]|
13614  *
13615  * Since: 1.4
13616  */
13617 void
13618 clutter_actor_add_action_with_name (ClutterActor  *self,
13619                                     const gchar   *name,
13620                                     ClutterAction *action)
13621 {
13622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13623   g_return_if_fail (name != NULL);
13624   g_return_if_fail (CLUTTER_IS_ACTION (action));
13625
13626   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13627   clutter_actor_add_action (self, action);
13628 }
13629
13630 /**
13631  * clutter_actor_remove_action:
13632  * @self: a #ClutterActor
13633  * @action: a #ClutterAction
13634  *
13635  * Removes @action from the list of actions applied to @self
13636  *
13637  * The reference held by @self on the #ClutterAction will be released
13638  *
13639  * Since: 1.4
13640  */
13641 void
13642 clutter_actor_remove_action (ClutterActor  *self,
13643                              ClutterAction *action)
13644 {
13645   ClutterActorPrivate *priv;
13646
13647   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13648   g_return_if_fail (CLUTTER_IS_ACTION (action));
13649
13650   priv = self->priv;
13651
13652   if (priv->actions == NULL)
13653     return;
13654
13655   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13656
13657   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13658 }
13659
13660 /**
13661  * clutter_actor_remove_action_by_name:
13662  * @self: a #ClutterActor
13663  * @name: the name of the action to remove
13664  *
13665  * Removes the #ClutterAction with the given name from the list
13666  * of actions applied to @self
13667  *
13668  * Since: 1.4
13669  */
13670 void
13671 clutter_actor_remove_action_by_name (ClutterActor *self,
13672                                      const gchar  *name)
13673 {
13674   ClutterActorPrivate *priv;
13675   ClutterActorMeta *meta;
13676
13677   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13678   g_return_if_fail (name != NULL);
13679
13680   priv = self->priv;
13681
13682   if (priv->actions == NULL)
13683     return;
13684
13685   meta = _clutter_meta_group_get_meta (priv->actions, name);
13686   if (meta == NULL)
13687     return;
13688
13689   _clutter_meta_group_remove_meta (priv->actions, meta);
13690
13691   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13692 }
13693
13694 /**
13695  * clutter_actor_get_actions:
13696  * @self: a #ClutterActor
13697  *
13698  * Retrieves the list of actions applied to @self
13699  *
13700  * Return value: (transfer container) (element-type Clutter.Action): a copy
13701  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13702  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13703  *   allocated by the returned #GList
13704  *
13705  * Since: 1.4
13706  */
13707 GList *
13708 clutter_actor_get_actions (ClutterActor *self)
13709 {
13710   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13711
13712   if (self->priv->actions == NULL)
13713     return NULL;
13714
13715   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13716 }
13717
13718 /**
13719  * clutter_actor_get_action:
13720  * @self: a #ClutterActor
13721  * @name: the name of the action to retrieve
13722  *
13723  * Retrieves the #ClutterAction with the given name in the list
13724  * of actions applied to @self
13725  *
13726  * Return value: (transfer none): a #ClutterAction for the given
13727  *   name, or %NULL. The returned #ClutterAction is owned by the
13728  *   actor and it should not be unreferenced directly
13729  *
13730  * Since: 1.4
13731  */
13732 ClutterAction *
13733 clutter_actor_get_action (ClutterActor *self,
13734                           const gchar  *name)
13735 {
13736   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13737   g_return_val_if_fail (name != NULL, NULL);
13738
13739   if (self->priv->actions == NULL)
13740     return NULL;
13741
13742   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13743 }
13744
13745 /**
13746  * clutter_actor_clear_actions:
13747  * @self: a #ClutterActor
13748  *
13749  * Clears the list of actions applied to @self
13750  *
13751  * Since: 1.4
13752  */
13753 void
13754 clutter_actor_clear_actions (ClutterActor *self)
13755 {
13756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13757
13758   if (self->priv->actions == NULL)
13759     return;
13760
13761   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13762 }
13763
13764 /**
13765  * clutter_actor_add_constraint:
13766  * @self: a #ClutterActor
13767  * @constraint: a #ClutterConstraint
13768  *
13769  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13770  * to @self
13771  *
13772  * The #ClutterActor will hold a reference on the @constraint until
13773  * either clutter_actor_remove_constraint() or
13774  * clutter_actor_clear_constraints() is called.
13775  *
13776  * Since: 1.4
13777  */
13778 void
13779 clutter_actor_add_constraint (ClutterActor      *self,
13780                               ClutterConstraint *constraint)
13781 {
13782   ClutterActorPrivate *priv;
13783
13784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13785   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13786
13787   priv = self->priv;
13788
13789   if (priv->constraints == NULL)
13790     {
13791       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13792       priv->constraints->actor = self;
13793     }
13794
13795   _clutter_meta_group_add_meta (priv->constraints,
13796                                 CLUTTER_ACTOR_META (constraint));
13797   clutter_actor_queue_relayout (self);
13798
13799   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13800 }
13801
13802 /**
13803  * clutter_actor_add_constraint_with_name:
13804  * @self: a #ClutterActor
13805  * @name: the name to set on the constraint
13806  * @constraint: a #ClutterConstraint
13807  *
13808  * A convenience function for setting the name of a #ClutterConstraint
13809  * while adding it to the list of constraints applied to @self
13810  *
13811  * This function is the logical equivalent of:
13812  *
13813  * |[
13814  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13815  *   clutter_actor_add_constraint (self, constraint);
13816  * ]|
13817  *
13818  * Since: 1.4
13819  */
13820 void
13821 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13822                                         const gchar       *name,
13823                                         ClutterConstraint *constraint)
13824 {
13825   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13826   g_return_if_fail (name != NULL);
13827   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13828
13829   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13830   clutter_actor_add_constraint (self, constraint);
13831 }
13832
13833 /**
13834  * clutter_actor_remove_constraint:
13835  * @self: a #ClutterActor
13836  * @constraint: a #ClutterConstraint
13837  *
13838  * Removes @constraint from the list of constraints applied to @self
13839  *
13840  * The reference held by @self on the #ClutterConstraint will be released
13841  *
13842  * Since: 1.4
13843  */
13844 void
13845 clutter_actor_remove_constraint (ClutterActor      *self,
13846                                  ClutterConstraint *constraint)
13847 {
13848   ClutterActorPrivate *priv;
13849
13850   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13851   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13852
13853   priv = self->priv;
13854
13855   if (priv->constraints == NULL)
13856     return;
13857
13858   _clutter_meta_group_remove_meta (priv->constraints,
13859                                    CLUTTER_ACTOR_META (constraint));
13860   clutter_actor_queue_relayout (self);
13861
13862   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13863 }
13864
13865 /**
13866  * clutter_actor_remove_constraint_by_name:
13867  * @self: a #ClutterActor
13868  * @name: the name of the constraint to remove
13869  *
13870  * Removes the #ClutterConstraint with the given name from the list
13871  * of constraints applied to @self
13872  *
13873  * Since: 1.4
13874  */
13875 void
13876 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13877                                          const gchar  *name)
13878 {
13879   ClutterActorPrivate *priv;
13880   ClutterActorMeta *meta;
13881
13882   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13883   g_return_if_fail (name != NULL);
13884
13885   priv = self->priv;
13886
13887   if (priv->constraints == NULL)
13888     return;
13889
13890   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13891   if (meta == NULL)
13892     return;
13893
13894   _clutter_meta_group_remove_meta (priv->constraints, meta);
13895   clutter_actor_queue_relayout (self);
13896 }
13897
13898 /**
13899  * clutter_actor_get_constraints:
13900  * @self: a #ClutterActor
13901  *
13902  * Retrieves the list of constraints applied to @self
13903  *
13904  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13905  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13906  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13907  *   allocated by the returned #GList
13908  *
13909  * Since: 1.4
13910  */
13911 GList *
13912 clutter_actor_get_constraints (ClutterActor *self)
13913 {
13914   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13915
13916   if (self->priv->constraints == NULL)
13917     return NULL;
13918
13919   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
13920 }
13921
13922 /**
13923  * clutter_actor_get_constraint:
13924  * @self: a #ClutterActor
13925  * @name: the name of the constraint to retrieve
13926  *
13927  * Retrieves the #ClutterConstraint with the given name in the list
13928  * of constraints applied to @self
13929  *
13930  * Return value: (transfer none): a #ClutterConstraint for the given
13931  *   name, or %NULL. The returned #ClutterConstraint is owned by the
13932  *   actor and it should not be unreferenced directly
13933  *
13934  * Since: 1.4
13935  */
13936 ClutterConstraint *
13937 clutter_actor_get_constraint (ClutterActor *self,
13938                               const gchar  *name)
13939 {
13940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13941   g_return_val_if_fail (name != NULL, NULL);
13942
13943   if (self->priv->constraints == NULL)
13944     return NULL;
13945
13946   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
13947 }
13948
13949 /**
13950  * clutter_actor_clear_constraints:
13951  * @self: a #ClutterActor
13952  *
13953  * Clears the list of constraints applied to @self
13954  *
13955  * Since: 1.4
13956  */
13957 void
13958 clutter_actor_clear_constraints (ClutterActor *self)
13959 {
13960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13961
13962   if (self->priv->constraints == NULL)
13963     return;
13964
13965   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
13966
13967   clutter_actor_queue_relayout (self);
13968 }
13969
13970 /**
13971  * clutter_actor_set_clip_to_allocation:
13972  * @self: a #ClutterActor
13973  * @clip_set: %TRUE to apply a clip tracking the allocation
13974  *
13975  * Sets whether @self should be clipped to the same size as its
13976  * allocation
13977  *
13978  * Since: 1.4
13979  */
13980 void
13981 clutter_actor_set_clip_to_allocation (ClutterActor *self,
13982                                       gboolean      clip_set)
13983 {
13984   ClutterActorPrivate *priv;
13985
13986   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13987
13988   clip_set = !!clip_set;
13989
13990   priv = self->priv;
13991
13992   if (priv->clip_to_allocation != clip_set)
13993     {
13994       priv->clip_to_allocation = clip_set;
13995
13996       clutter_actor_queue_redraw (self);
13997
13998       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
13999     }
14000 }
14001
14002 /**
14003  * clutter_actor_get_clip_to_allocation:
14004  * @self: a #ClutterActor
14005  *
14006  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14007  *
14008  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14009  *
14010  * Since: 1.4
14011  */
14012 gboolean
14013 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14014 {
14015   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14016
14017   return self->priv->clip_to_allocation;
14018 }
14019
14020 /**
14021  * clutter_actor_add_effect:
14022  * @self: a #ClutterActor
14023  * @effect: a #ClutterEffect
14024  *
14025  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14026  *
14027  * The #ClutterActor will hold a reference on the @effect until either
14028  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14029  * called.
14030  *
14031  * Since: 1.4
14032  */
14033 void
14034 clutter_actor_add_effect (ClutterActor  *self,
14035                           ClutterEffect *effect)
14036 {
14037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14038   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14039
14040   _clutter_actor_add_effect_internal (self, effect);
14041
14042   clutter_actor_queue_redraw (self);
14043
14044   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14045 }
14046
14047 /**
14048  * clutter_actor_add_effect_with_name:
14049  * @self: a #ClutterActor
14050  * @name: the name to set on the effect
14051  * @effect: a #ClutterEffect
14052  *
14053  * A convenience function for setting the name of a #ClutterEffect
14054  * while adding it to the list of effectss applied to @self
14055  *
14056  * This function is the logical equivalent of:
14057  *
14058  * |[
14059  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14060  *   clutter_actor_add_effect (self, effect);
14061  * ]|
14062  *
14063  * Since: 1.4
14064  */
14065 void
14066 clutter_actor_add_effect_with_name (ClutterActor  *self,
14067                                     const gchar   *name,
14068                                     ClutterEffect *effect)
14069 {
14070   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14071   g_return_if_fail (name != NULL);
14072   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14073
14074   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14075   clutter_actor_add_effect (self, effect);
14076 }
14077
14078 /**
14079  * clutter_actor_remove_effect:
14080  * @self: a #ClutterActor
14081  * @effect: a #ClutterEffect
14082  *
14083  * Removes @effect from the list of effects applied to @self
14084  *
14085  * The reference held by @self on the #ClutterEffect will be released
14086  *
14087  * Since: 1.4
14088  */
14089 void
14090 clutter_actor_remove_effect (ClutterActor  *self,
14091                              ClutterEffect *effect)
14092 {
14093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14094   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14095
14096   _clutter_actor_remove_effect_internal (self, effect);
14097
14098   clutter_actor_queue_redraw (self);
14099
14100   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14101 }
14102
14103 /**
14104  * clutter_actor_remove_effect_by_name:
14105  * @self: a #ClutterActor
14106  * @name: the name of the effect to remove
14107  *
14108  * Removes the #ClutterEffect with the given name from the list
14109  * of effects applied to @self
14110  *
14111  * Since: 1.4
14112  */
14113 void
14114 clutter_actor_remove_effect_by_name (ClutterActor *self,
14115                                      const gchar  *name)
14116 {
14117   ClutterActorPrivate *priv;
14118   ClutterActorMeta *meta;
14119
14120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14121   g_return_if_fail (name != NULL);
14122
14123   priv = self->priv;
14124
14125   if (priv->effects == NULL)
14126     return;
14127
14128   meta = _clutter_meta_group_get_meta (priv->effects, name);
14129   if (meta == NULL)
14130     return;
14131
14132   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14133 }
14134
14135 /**
14136  * clutter_actor_get_effects:
14137  * @self: a #ClutterActor
14138  *
14139  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14140  *
14141  * Return value: (transfer container) (element-type Clutter.Effect): a list
14142  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14143  *   list are owned by Clutter and they should not be freed. You should
14144  *   free the returned list using g_list_free() when done
14145  *
14146  * Since: 1.4
14147  */
14148 GList *
14149 clutter_actor_get_effects (ClutterActor *self)
14150 {
14151   ClutterActorPrivate *priv;
14152
14153   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14154
14155   priv = self->priv;
14156
14157   if (priv->effects == NULL)
14158     return NULL;
14159
14160   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14161 }
14162
14163 /**
14164  * clutter_actor_get_effect:
14165  * @self: a #ClutterActor
14166  * @name: the name of the effect to retrieve
14167  *
14168  * Retrieves the #ClutterEffect with the given name in the list
14169  * of effects applied to @self
14170  *
14171  * Return value: (transfer none): a #ClutterEffect for the given
14172  *   name, or %NULL. The returned #ClutterEffect is owned by the
14173  *   actor and it should not be unreferenced directly
14174  *
14175  * Since: 1.4
14176  */
14177 ClutterEffect *
14178 clutter_actor_get_effect (ClutterActor *self,
14179                           const gchar  *name)
14180 {
14181   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14182   g_return_val_if_fail (name != NULL, NULL);
14183
14184   if (self->priv->effects == NULL)
14185     return NULL;
14186
14187   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14188 }
14189
14190 /**
14191  * clutter_actor_clear_effects:
14192  * @self: a #ClutterActor
14193  *
14194  * Clears the list of effects applied to @self
14195  *
14196  * Since: 1.4
14197  */
14198 void
14199 clutter_actor_clear_effects (ClutterActor *self)
14200 {
14201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14202
14203   if (self->priv->effects == NULL)
14204     return;
14205
14206   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14207
14208   clutter_actor_queue_redraw (self);
14209 }
14210
14211 /**
14212  * clutter_actor_has_key_focus:
14213  * @self: a #ClutterActor
14214  *
14215  * Checks whether @self is the #ClutterActor that has key focus
14216  *
14217  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14218  *
14219  * Since: 1.4
14220  */
14221 gboolean
14222 clutter_actor_has_key_focus (ClutterActor *self)
14223 {
14224   ClutterActor *stage;
14225
14226   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14227
14228   stage = _clutter_actor_get_stage_internal (self);
14229   if (stage == NULL)
14230     return FALSE;
14231
14232   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14233 }
14234
14235 static gboolean
14236 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14237                                       ClutterPaintVolume *pv)
14238 {
14239   ClutterActorPrivate *priv = self->priv;
14240
14241   /* Actors are only expected to report a valid paint volume
14242    * while they have a valid allocation. */
14243   if (G_UNLIKELY (priv->needs_allocation))
14244     {
14245       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14246                     "Actor needs allocation",
14247                     _clutter_actor_get_debug_name (self));
14248       return FALSE;
14249     }
14250
14251   /* Check if there are any handlers connected to the paint
14252    * signal. If there are then all bets are off for what the paint
14253    * volume for this actor might possibly be!
14254    *
14255    * XXX: It's expected that this is going to end up being quite a
14256    * costly check to have to do here, but we haven't come up with
14257    * another solution that can reliably catch paint signal handlers at
14258    * the right time to either avoid artefacts due to invalid stage
14259    * clipping or due to incorrect culling.
14260    *
14261    * Previously we checked in clutter_actor_paint(), but at that time
14262    * we may already be using a stage clip that could be derived from
14263    * an invalid paint-volume. We used to try and handle that by
14264    * queuing a follow up, unclipped, redraw but still the previous
14265    * checking wasn't enough to catch invalid volumes involved in
14266    * culling (considering that containers may derive their volume from
14267    * children that haven't yet been painted)
14268    *
14269    * Longer term, improved solutions could be:
14270    * - Disallow painting in the paint signal, only allow using it
14271    *   for tracking when paints happen. We can add another API that
14272    *   allows monkey patching the paint of arbitrary actors but in a
14273    *   more controlled way and that also supports modifying the
14274    *   paint-volume.
14275    * - If we could be notified somehow when signal handlers are
14276    *   connected we wouldn't have to poll for handlers like this.
14277    */
14278   if (g_signal_has_handler_pending (self,
14279                                     actor_signals[PAINT],
14280                                     0,
14281                                     TRUE))
14282     {
14283       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14284                     "Actor has \"paint\" signal handlers",
14285                     _clutter_actor_get_debug_name (self));
14286       return FALSE;
14287     }
14288
14289   _clutter_paint_volume_init_static (pv, self);
14290
14291   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14292     {
14293       clutter_paint_volume_free (pv);
14294       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14295                     "Actor failed to report a volume",
14296                     _clutter_actor_get_debug_name (self));
14297       return FALSE;
14298     }
14299
14300   /* since effects can modify the paint volume, we allow them to actually
14301    * do this by making get_paint_volume() "context sensitive"
14302    */
14303   if (priv->effects != NULL)
14304     {
14305       if (priv->current_effect != NULL)
14306         {
14307           const GList *effects, *l;
14308
14309           /* if we are being called from within the paint sequence of
14310            * an actor, get the paint volume up to the current effect
14311            */
14312           effects = _clutter_meta_group_peek_metas (priv->effects);
14313           for (l = effects;
14314                l != NULL || (l != NULL && l->data != priv->current_effect);
14315                l = l->next)
14316             {
14317               if (!_clutter_effect_get_paint_volume (l->data, pv))
14318                 {
14319                   clutter_paint_volume_free (pv);
14320                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14321                                 "Effect (%s) failed to report a volume",
14322                                 _clutter_actor_get_debug_name (self),
14323                                 _clutter_actor_meta_get_debug_name (l->data));
14324                   return FALSE;
14325                 }
14326             }
14327         }
14328       else
14329         {
14330           const GList *effects, *l;
14331
14332           /* otherwise, get the cumulative volume */
14333           effects = _clutter_meta_group_peek_metas (priv->effects);
14334           for (l = effects; l != NULL; l = l->next)
14335             if (!_clutter_effect_get_paint_volume (l->data, pv))
14336               {
14337                 clutter_paint_volume_free (pv);
14338                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14339                               "Effect (%s) failed to report a volume",
14340                               _clutter_actor_get_debug_name (self),
14341                               _clutter_actor_meta_get_debug_name (l->data));
14342                 return FALSE;
14343               }
14344         }
14345     }
14346
14347   return TRUE;
14348 }
14349
14350 /* The public clutter_actor_get_paint_volume API returns a const
14351  * pointer since we return a pointer directly to the cached
14352  * PaintVolume associated with the actor and don't want the user to
14353  * inadvertently modify it, but for internal uses we sometimes need
14354  * access to the same PaintVolume but need to apply some book-keeping
14355  * modifications to it so we don't want a const pointer.
14356  */
14357 static ClutterPaintVolume *
14358 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14359 {
14360   ClutterActorPrivate *priv;
14361
14362   priv = self->priv;
14363
14364   if (priv->paint_volume_valid)
14365     clutter_paint_volume_free (&priv->paint_volume);
14366
14367   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14368     {
14369       priv->paint_volume_valid = TRUE;
14370       return &priv->paint_volume;
14371     }
14372   else
14373     {
14374       priv->paint_volume_valid = FALSE;
14375       return NULL;
14376     }
14377 }
14378
14379 /**
14380  * clutter_actor_get_paint_volume:
14381  * @self: a #ClutterActor
14382  *
14383  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14384  * when a paint volume can't be determined.
14385  *
14386  * The paint volume is defined as the 3D space occupied by an actor
14387  * when being painted.
14388  *
14389  * This function will call the <function>get_paint_volume()</function>
14390  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14391  * should not usually care about overriding the default implementation,
14392  * unless they are, for instance: painting outside their allocation, or
14393  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14394  * 3D depth).
14395  *
14396  * <note>2D actors overriding <function>get_paint_volume()</function>
14397  * ensure their volume has a depth of 0. (This will be true so long as
14398  * you don't call clutter_paint_volume_set_depth().)</note>
14399  *
14400  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14401  *   or %NULL if no volume could be determined.
14402  *
14403  * Since: 1.6
14404  */
14405 const ClutterPaintVolume *
14406 clutter_actor_get_paint_volume (ClutterActor *self)
14407 {
14408   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14409
14410   return _clutter_actor_get_paint_volume_mutable (self);
14411 }
14412
14413 /**
14414  * clutter_actor_get_transformed_paint_volume:
14415  * @self: a #ClutterActor
14416  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14417  *    (or %NULL for the stage)
14418  *
14419  * Retrieves the 3D paint volume of an actor like
14420  * clutter_actor_get_paint_volume() does (Please refer to the
14421  * documentation of clutter_actor_get_paint_volume() for more
14422  * details.) and it additionally transforms the paint volume into the
14423  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14424  * is passed for @relative_to_ancestor)
14425  *
14426  * This can be used by containers that base their paint volume on
14427  * the volume of their children. Such containers can query the
14428  * transformed paint volume of all of its children and union them
14429  * together using clutter_paint_volume_union().
14430  *
14431  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14432  *   or %NULL if no volume could be determined.
14433  *
14434  * Since: 1.6
14435  */
14436 const ClutterPaintVolume *
14437 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14438                                             ClutterActor *relative_to_ancestor)
14439 {
14440   const ClutterPaintVolume *volume;
14441   ClutterActor *stage;
14442   ClutterPaintVolume *transformed_volume;
14443
14444   stage = _clutter_actor_get_stage_internal (self);
14445   if (G_UNLIKELY (stage == NULL))
14446     return NULL;
14447
14448   if (relative_to_ancestor == NULL)
14449     relative_to_ancestor = stage;
14450
14451   volume = clutter_actor_get_paint_volume (self);
14452   if (volume == NULL)
14453     return NULL;
14454
14455   transformed_volume =
14456     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14457
14458   _clutter_paint_volume_copy_static (volume, transformed_volume);
14459
14460   _clutter_paint_volume_transform_relative (transformed_volume,
14461                                             relative_to_ancestor);
14462
14463   return transformed_volume;
14464 }
14465
14466 /**
14467  * clutter_actor_get_paint_box:
14468  * @self: a #ClutterActor
14469  * @box: (out): return location for a #ClutterActorBox
14470  *
14471  * Retrieves the paint volume of the passed #ClutterActor, and
14472  * transforms it into a 2D bounding box in stage coordinates.
14473  *
14474  * This function is useful to determine the on screen area occupied by
14475  * the actor. The box is only an approximation and may often be
14476  * considerably larger due to the optimizations used to calculate the
14477  * box. The box is never smaller though, so it can reliably be used
14478  * for culling.
14479  *
14480  * There are times when a 2D paint box can't be determined, e.g.
14481  * because the actor isn't yet parented under a stage or because
14482  * the actor is unable to determine a paint volume.
14483  *
14484  * Return value: %TRUE if a 2D paint box could be determined, else
14485  * %FALSE.
14486  *
14487  * Since: 1.6
14488  */
14489 gboolean
14490 clutter_actor_get_paint_box (ClutterActor    *self,
14491                              ClutterActorBox *box)
14492 {
14493   ClutterActor *stage;
14494   ClutterPaintVolume *pv;
14495
14496   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14497   g_return_val_if_fail (box != NULL, FALSE);
14498
14499   stage = _clutter_actor_get_stage_internal (self);
14500   if (G_UNLIKELY (!stage))
14501     return FALSE;
14502
14503   pv = _clutter_actor_get_paint_volume_mutable (self);
14504   if (G_UNLIKELY (!pv))
14505     return FALSE;
14506
14507   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14508
14509   return TRUE;
14510 }
14511
14512 /**
14513  * clutter_actor_has_overlaps:
14514  * @self: A #ClutterActor
14515  *
14516  * Asks the actor's implementation whether it may contain overlapping
14517  * primitives.
14518  *
14519  * For example; Clutter may use this to determine whether the painting
14520  * should be redirected to an offscreen buffer to correctly implement
14521  * the opacity property.
14522  *
14523  * Custom actors can override the default response by implementing the
14524  * #ClutterActor <function>has_overlaps</function> virtual function. See
14525  * clutter_actor_set_offscreen_redirect() for more information.
14526  *
14527  * Return value: %TRUE if the actor may have overlapping primitives, and
14528  *   %FALSE otherwise
14529  *
14530  * Since: 1.8
14531  */
14532 gboolean
14533 clutter_actor_has_overlaps (ClutterActor *self)
14534 {
14535   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14536
14537   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14538 }
14539
14540 /**
14541  * clutter_actor_has_effects:
14542  * @self: A #ClutterActor
14543  *
14544  * Returns whether the actor has any effects applied.
14545  *
14546  * Return value: %TRUE if the actor has any effects,
14547  *   %FALSE otherwise
14548  *
14549  * Since: 1.10
14550  */
14551 gboolean
14552 clutter_actor_has_effects (ClutterActor *self)
14553 {
14554   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14555
14556   if (self->priv->effects == NULL)
14557     return FALSE;
14558
14559   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14560 }
14561
14562 /**
14563  * clutter_actor_has_constraints:
14564  * @self: A #ClutterActor
14565  *
14566  * Returns whether the actor has any constraints applied.
14567  *
14568  * Return value: %TRUE if the actor has any constraints,
14569  *   %FALSE otherwise
14570  *
14571  * Since: 1.10
14572  */
14573 gboolean
14574 clutter_actor_has_constraints (ClutterActor *self)
14575 {
14576   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14577
14578   return self->priv->constraints != NULL;
14579 }
14580
14581 /**
14582  * clutter_actor_has_actions:
14583  * @self: A #ClutterActor
14584  *
14585  * Returns whether the actor has any actions applied.
14586  *
14587  * Return value: %TRUE if the actor has any actions,
14588  *   %FALSE otherwise
14589  *
14590  * Since: 1.10
14591  */
14592 gboolean
14593 clutter_actor_has_actions (ClutterActor *self)
14594 {
14595   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14596
14597   return self->priv->actions != NULL;
14598 }
14599
14600 /**
14601  * clutter_actor_get_n_children:
14602  * @self: a #ClutterActor
14603  *
14604  * Retrieves the number of children of @self.
14605  *
14606  * Return value: the number of children of an actor
14607  *
14608  * Since: 1.10
14609  */
14610 gint
14611 clutter_actor_get_n_children (ClutterActor *self)
14612 {
14613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14614
14615   return self->priv->n_children;
14616 }
14617
14618 /**
14619  * clutter_actor_get_child_at_index:
14620  * @self: a #ClutterActor
14621  * @index_: the position in the list of children
14622  *
14623  * Retrieves the actor at the given @index_ inside the list of
14624  * children of @self.
14625  *
14626  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14627  *
14628  * Since: 1.10
14629  */
14630 ClutterActor *
14631 clutter_actor_get_child_at_index (ClutterActor *self,
14632                                   gint          index_)
14633 {
14634   ClutterActor *iter;
14635   int i;
14636
14637   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14638   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14639
14640   for (iter = self->priv->first_child, i = 0;
14641        iter != NULL && i < index_;
14642        iter = iter->priv->next_sibling, i += 1)
14643     ;
14644
14645   return iter;
14646 }
14647
14648 /*< private >
14649  * _clutter_actor_foreach_child:
14650  * @actor: The actor whos children you want to iterate
14651  * @callback: The function to call for each child
14652  * @user_data: Private data to pass to @callback
14653  *
14654  * Calls a given @callback once for each child of the specified @actor and
14655  * passing the @user_data pointer each time.
14656  *
14657  * Return value: returns %TRUE if all children were iterated, else
14658  *    %FALSE if a callback broke out of iteration early.
14659  */
14660 gboolean
14661 _clutter_actor_foreach_child (ClutterActor           *self,
14662                               ClutterForeachCallback  callback,
14663                               gpointer                user_data)
14664 {
14665   ClutterActorPrivate *priv = self->priv;
14666   ClutterActor *iter;
14667   gboolean cont;
14668
14669   for (cont = TRUE, iter = priv->first_child;
14670        cont && iter != NULL;
14671        iter = iter->priv->next_sibling)
14672     {
14673       cont = callback (iter, user_data);
14674     }
14675
14676   return cont;
14677 }
14678
14679 /* For debugging purposes this gives us a simple way to print out
14680  * the scenegraph e.g in gdb using:
14681  * [|
14682  *   _clutter_actor_traverse (stage,
14683  *                            0,
14684  *                            _clutter_debug_print_actor_cb,
14685  *                            NULL,
14686  *                            NULL);
14687  * |]
14688  */
14689 ClutterActorTraverseVisitFlags
14690 _clutter_debug_print_actor_cb (ClutterActor *actor,
14691                                int depth,
14692                                void *user_data)
14693 {
14694   g_print ("%*s%s:%p\n",
14695            depth * 2, "",
14696            _clutter_actor_get_debug_name (actor),
14697            actor);
14698
14699   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14700 }
14701
14702 static void
14703 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14704                                  ClutterTraverseCallback callback,
14705                                  gpointer                user_data)
14706 {
14707   GQueue *queue = g_queue_new ();
14708   ClutterActor dummy;
14709   int current_depth = 0;
14710
14711   g_queue_push_tail (queue, actor);
14712   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14713
14714   while ((actor = g_queue_pop_head (queue)))
14715     {
14716       ClutterActorTraverseVisitFlags flags;
14717
14718       if (actor == &dummy)
14719         {
14720           current_depth++;
14721           g_queue_push_tail (queue, &dummy);
14722           continue;
14723         }
14724
14725       flags = callback (actor, current_depth, user_data);
14726       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14727         break;
14728       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14729         {
14730           ClutterActor *iter;
14731
14732           for (iter = actor->priv->first_child;
14733                iter != NULL;
14734                iter = iter->priv->next_sibling)
14735             {
14736               g_queue_push_tail (queue, iter);
14737             }
14738         }
14739     }
14740
14741   g_queue_free (queue);
14742 }
14743
14744 static ClutterActorTraverseVisitFlags
14745 _clutter_actor_traverse_depth (ClutterActor           *actor,
14746                                ClutterTraverseCallback before_children_callback,
14747                                ClutterTraverseCallback after_children_callback,
14748                                int                     current_depth,
14749                                gpointer                user_data)
14750 {
14751   ClutterActorTraverseVisitFlags flags;
14752
14753   flags = before_children_callback (actor, current_depth, user_data);
14754   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14755     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14756
14757   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14758     {
14759       ClutterActor *iter;
14760
14761       for (iter = actor->priv->first_child;
14762            iter != NULL;
14763            iter = iter->priv->next_sibling)
14764         {
14765           flags = _clutter_actor_traverse_depth (iter,
14766                                                  before_children_callback,
14767                                                  after_children_callback,
14768                                                  current_depth + 1,
14769                                                  user_data);
14770
14771           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14772             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14773         }
14774     }
14775
14776   if (after_children_callback)
14777     return after_children_callback (actor, current_depth, user_data);
14778   else
14779     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14780 }
14781
14782 /* _clutter_actor_traverse:
14783  * @actor: The actor to start traversing the graph from
14784  * @flags: These flags may affect how the traversal is done
14785  * @before_children_callback: A function to call before visiting the
14786  *   children of the current actor.
14787  * @after_children_callback: A function to call after visiting the
14788  *   children of the current actor. (Ignored if
14789  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14790  * @user_data: The private data to pass to the callbacks
14791  *
14792  * Traverses the scenegraph starting at the specified @actor and
14793  * descending through all its children and its children's children.
14794  * For each actor traversed @before_children_callback and
14795  * @after_children_callback are called with the specified
14796  * @user_data, before and after visiting that actor's children.
14797  *
14798  * The callbacks can return flags that affect the ongoing traversal
14799  * such as by skipping over an actors children or bailing out of
14800  * any further traversing.
14801  */
14802 void
14803 _clutter_actor_traverse (ClutterActor              *actor,
14804                          ClutterActorTraverseFlags  flags,
14805                          ClutterTraverseCallback    before_children_callback,
14806                          ClutterTraverseCallback    after_children_callback,
14807                          gpointer                   user_data)
14808 {
14809   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14810     _clutter_actor_traverse_breadth (actor,
14811                                      before_children_callback,
14812                                      user_data);
14813   else /* DEPTH_FIRST */
14814     _clutter_actor_traverse_depth (actor,
14815                                    before_children_callback,
14816                                    after_children_callback,
14817                                    0, /* start depth */
14818                                    user_data);
14819 }
14820
14821 static void
14822 on_layout_manager_changed (ClutterLayoutManager *manager,
14823                            ClutterActor         *self)
14824 {
14825   clutter_actor_queue_relayout (self);
14826 }
14827
14828 /**
14829  * clutter_actor_set_layout_manager:
14830  * @self: a #ClutterActor
14831  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14832  *
14833  * Sets the #ClutterLayoutManager delegate object that will be used to
14834  * lay out the children of @self.
14835  *
14836  * The #ClutterActor will take a reference on the passed @manager which
14837  * will be released either when the layout manager is removed, or when
14838  * the actor is destroyed.
14839  *
14840  * Since: 1.10
14841  */
14842 void
14843 clutter_actor_set_layout_manager (ClutterActor         *self,
14844                                   ClutterLayoutManager *manager)
14845 {
14846   ClutterActorPrivate *priv;
14847
14848   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14849   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14850
14851   priv = self->priv;
14852
14853   if (priv->layout_manager != NULL)
14854     {
14855       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14856                                             G_CALLBACK (on_layout_manager_changed),
14857                                             self);
14858       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14859       g_object_unref (priv->layout_manager);
14860     }
14861
14862   priv->layout_manager = manager;
14863
14864   if (priv->layout_manager != NULL)
14865     {
14866       g_object_ref_sink (priv->layout_manager);
14867       clutter_layout_manager_set_container (priv->layout_manager,
14868                                             CLUTTER_CONTAINER (self));
14869       g_signal_connect (priv->layout_manager, "layout-changed",
14870                         G_CALLBACK (on_layout_manager_changed),
14871                         self);
14872     }
14873
14874   clutter_actor_queue_relayout (self);
14875
14876   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14877 }
14878
14879 /**
14880  * clutter_actor_get_layout_manager:
14881  * @self: a #ClutterActor
14882  *
14883  * Retrieves the #ClutterLayoutManager used by @self.
14884  *
14885  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14886  *   or %NULL
14887  *
14888  * Since: 1.10
14889  */
14890 ClutterLayoutManager *
14891 clutter_actor_get_layout_manager (ClutterActor *self)
14892 {
14893   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14894
14895   return self->priv->layout_manager;
14896 }
14897
14898 static const ClutterLayoutInfo default_layout_info = {
14899   0.f,                          /* fixed-x */
14900   0.f,                          /* fixed-y */
14901   { 0, 0, 0, 0 },               /* margin */
14902   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14903   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14904   0.f, 0.f,                     /* min_width, natural_width */
14905   0.f, 0.f,                     /* natual_width, natural_height */
14906 };
14907
14908 static void
14909 layout_info_free (gpointer data)
14910 {
14911   if (G_LIKELY (data != NULL))
14912     g_slice_free (ClutterLayoutInfo, data);
14913 }
14914
14915 /*< private >
14916  * _clutter_actor_get_layout_info:
14917  * @self: a #ClutterActor
14918  *
14919  * Retrieves a pointer to the ClutterLayoutInfo structure.
14920  *
14921  * If the actor does not have a ClutterLayoutInfo associated to it, one
14922  * will be created and initialized to the default values.
14923  *
14924  * This function should be used for setters.
14925  *
14926  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
14927  * instead.
14928  *
14929  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
14930  */
14931 ClutterLayoutInfo *
14932 _clutter_actor_get_layout_info (ClutterActor *self)
14933 {
14934   ClutterLayoutInfo *retval;
14935
14936   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14937   if (retval == NULL)
14938     {
14939       retval = g_slice_new (ClutterLayoutInfo);
14940
14941       *retval = default_layout_info;
14942
14943       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
14944                                retval,
14945                                layout_info_free);
14946     }
14947
14948   return retval;
14949 }
14950
14951 /*< private >
14952  * _clutter_actor_get_layout_info_or_defaults:
14953  * @self: a #ClutterActor
14954  *
14955  * Retrieves the ClutterLayoutInfo structure associated to an actor.
14956  *
14957  * If the actor does not have a ClutterLayoutInfo structure associated to it,
14958  * then the default structure will be returned.
14959  *
14960  * This function should only be used for getters.
14961  *
14962  * Return value: a const pointer to the ClutterLayoutInfo structure
14963  */
14964 const ClutterLayoutInfo *
14965 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
14966 {
14967   const ClutterLayoutInfo *info;
14968
14969   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14970   if (info == NULL)
14971     return &default_layout_info;
14972
14973   return info;
14974 }
14975
14976 /**
14977  * clutter_actor_set_x_align:
14978  * @self: a #ClutterActor
14979  * @x_align: the horizontal alignment policy
14980  *
14981  * Sets the horizontal alignment policy of a #ClutterActor, in case the
14982  * actor received extra horizontal space.
14983  *
14984  * See also the #ClutterActor:x-align property.
14985  *
14986  * Since: 1.10
14987  */
14988 void
14989 clutter_actor_set_x_align (ClutterActor      *self,
14990                            ClutterActorAlign  x_align)
14991 {
14992   ClutterLayoutInfo *info;
14993
14994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995
14996   info = _clutter_actor_get_layout_info (self);
14997
14998   if (info->x_align != x_align)
14999     {
15000       info->x_align = x_align;
15001
15002       clutter_actor_queue_relayout (self);
15003
15004       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15005     }
15006 }
15007
15008 /**
15009  * clutter_actor_get_x_align:
15010  * @self: a #ClutterActor
15011  *
15012  * Retrieves the horizontal alignment policy set using
15013  * clutter_actor_set_x_align().
15014  *
15015  * Return value: the horizontal alignment policy.
15016  *
15017  * Since: 1.10
15018  */
15019 ClutterActorAlign
15020 clutter_actor_get_x_align (ClutterActor *self)
15021 {
15022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15023
15024   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15025 }
15026
15027 /**
15028  * clutter_actor_set_y_align:
15029  * @self: a #ClutterActor
15030  * @y_align: the vertical alignment policy
15031  *
15032  * Sets the vertical alignment policy of a #ClutterActor, in case the
15033  * actor received extra vertical space.
15034  *
15035  * See also the #ClutterActor:y-align property.
15036  *
15037  * Since: 1.10
15038  */
15039 void
15040 clutter_actor_set_y_align (ClutterActor      *self,
15041                            ClutterActorAlign  y_align)
15042 {
15043   ClutterLayoutInfo *info;
15044
15045   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15046
15047   info = _clutter_actor_get_layout_info (self);
15048
15049   if (info->y_align != y_align)
15050     {
15051       info->y_align = y_align;
15052
15053       clutter_actor_queue_relayout (self);
15054
15055       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15056     }
15057 }
15058
15059 /**
15060  * clutter_actor_get_y_align:
15061  * @self: a #ClutterActor
15062  *
15063  * Retrieves the vertical alignment policy set using
15064  * clutter_actor_set_y_align().
15065  *
15066  * Return value: the vertical alignment policy.
15067  *
15068  * Since: 1.10
15069  */
15070 ClutterActorAlign
15071 clutter_actor_get_y_align (ClutterActor *self)
15072 {
15073   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15074
15075   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15076 }
15077
15078
15079 /**
15080  * clutter_margin_new:
15081  *
15082  * Creates a new #ClutterMargin.
15083  *
15084  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15085  *   clutter_margin_free() to free the resources associated with it when
15086  *   done.
15087  *
15088  * Since: 1.10
15089  */
15090 ClutterMargin *
15091 clutter_margin_new (void)
15092 {
15093   return g_slice_new0 (ClutterMargin);
15094 }
15095
15096 /**
15097  * clutter_margin_copy:
15098  * @margin_: a #ClutterMargin
15099  *
15100  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15101  * the newly created structure.
15102  *
15103  * Return value: (transfer full): a copy of the #ClutterMargin.
15104  *
15105  * Since: 1.10
15106  */
15107 ClutterMargin *
15108 clutter_margin_copy (const ClutterMargin *margin_)
15109 {
15110   if (G_LIKELY (margin_ != NULL))
15111     return g_slice_dup (ClutterMargin, margin_);
15112
15113   return NULL;
15114 }
15115
15116 /**
15117  * clutter_margin_free:
15118  * @margin_: a #ClutterMargin
15119  *
15120  * Frees the resources allocated by clutter_margin_new() and
15121  * clutter_margin_copy().
15122  *
15123  * Since: 1.10
15124  */
15125 void
15126 clutter_margin_free (ClutterMargin *margin_)
15127 {
15128   if (G_LIKELY (margin_ != NULL))
15129     g_slice_free (ClutterMargin, margin_);
15130 }
15131
15132 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15133                      clutter_margin_copy,
15134                      clutter_margin_free)
15135
15136 /**
15137  * clutter_actor_set_margin:
15138  * @self: a #ClutterActor
15139  * @margin: a #ClutterMargin
15140  *
15141  * Sets all the components of the margin of a #ClutterActor.
15142  *
15143  * Since: 1.10
15144  */
15145 void
15146 clutter_actor_set_margin (ClutterActor        *self,
15147                           const ClutterMargin *margin)
15148 {
15149   ClutterLayoutInfo *info;
15150   gboolean changed;
15151   GObject *obj;
15152
15153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15154   g_return_if_fail (margin != NULL);
15155
15156   obj = G_OBJECT (self);
15157   changed = FALSE;
15158
15159   g_object_freeze_notify (obj);
15160
15161   info = _clutter_actor_get_layout_info (self);
15162
15163   if (info->margin.top != margin->top)
15164     {
15165       info->margin.top = margin->top;
15166       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15167       changed = TRUE;
15168     }
15169
15170   if (info->margin.right != margin->right)
15171     {
15172       info->margin.right = margin->right;
15173       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15174       changed = TRUE;
15175     }
15176
15177   if (info->margin.bottom != margin->bottom)
15178     {
15179       info->margin.bottom = margin->bottom;
15180       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15181       changed = TRUE;
15182     }
15183
15184   if (info->margin.left != margin->left)
15185     {
15186       info->margin.left = margin->left;
15187       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15188       changed = TRUE;
15189     }
15190
15191   if (changed)
15192     clutter_actor_queue_relayout (self);
15193
15194   g_object_thaw_notify (obj);
15195 }
15196
15197 /**
15198  * clutter_actor_get_margin:
15199  * @self: a #ClutterActor
15200  * @margin: (out caller-allocates): return location for a #ClutterMargin
15201  *
15202  * Retrieves all the components of the margin of a #ClutterActor.
15203  *
15204  * Since: 1.10
15205  */
15206 void
15207 clutter_actor_get_margin (ClutterActor  *self,
15208                           ClutterMargin *margin)
15209 {
15210   const ClutterLayoutInfo *info;
15211
15212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15213   g_return_if_fail (margin != NULL);
15214
15215   info = _clutter_actor_get_layout_info_or_defaults (self);
15216
15217   *margin = info->margin;
15218 }
15219
15220 /**
15221  * clutter_actor_set_margin_top:
15222  * @self: a #ClutterActor
15223  * @margin: the top margin
15224  *
15225  * Sets the margin from the top of a #ClutterActor.
15226  *
15227  * Since: 1.10
15228  */
15229 void
15230 clutter_actor_set_margin_top (ClutterActor *self,
15231                               gfloat        margin)
15232 {
15233   ClutterLayoutInfo *info;
15234
15235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15236   g_return_if_fail (margin >= 0.f);
15237
15238   info = _clutter_actor_get_layout_info (self);
15239
15240   if (info->margin.top == margin)
15241     return;
15242
15243   info->margin.top = margin;
15244
15245   clutter_actor_queue_relayout (self);
15246
15247   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15248 }
15249
15250 /**
15251  * clutter_actor_get_margin_top:
15252  * @self: a #ClutterActor
15253  *
15254  * Retrieves the top margin of a #ClutterActor.
15255  *
15256  * Return value: the top margin
15257  *
15258  * Since: 1.10
15259  */
15260 gfloat
15261 clutter_actor_get_margin_top (ClutterActor *self)
15262 {
15263   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15264
15265   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15266 }
15267
15268 /**
15269  * clutter_actor_set_margin_bottom:
15270  * @self: a #ClutterActor
15271  * @margin: the bottom margin
15272  *
15273  * Sets the margin from the bottom of a #ClutterActor.
15274  *
15275  * Since: 1.10
15276  */
15277 void
15278 clutter_actor_set_margin_bottom (ClutterActor *self,
15279                                  gfloat        margin)
15280 {
15281   ClutterLayoutInfo *info;
15282
15283   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15284   g_return_if_fail (margin >= 0.f);
15285
15286   info = _clutter_actor_get_layout_info (self);
15287
15288   if (info->margin.bottom == margin)
15289     return;
15290
15291   info->margin.bottom = margin;
15292
15293   clutter_actor_queue_relayout (self);
15294
15295   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15296 }
15297
15298 /**
15299  * clutter_actor_get_margin_bottom:
15300  * @self: a #ClutterActor
15301  *
15302  * Retrieves the bottom margin of a #ClutterActor.
15303  *
15304  * Return value: the bottom margin
15305  *
15306  * Since: 1.10
15307  */
15308 gfloat
15309 clutter_actor_get_margin_bottom (ClutterActor *self)
15310 {
15311   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15312
15313   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15314 }
15315
15316 /**
15317  * clutter_actor_set_margin_left:
15318  * @self: a #ClutterActor
15319  * @margin: the left margin
15320  *
15321  * Sets the margin from the left of a #ClutterActor.
15322  *
15323  * Since: 1.10
15324  */
15325 void
15326 clutter_actor_set_margin_left (ClutterActor *self,
15327                                gfloat        margin)
15328 {
15329   ClutterLayoutInfo *info;
15330
15331   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15332   g_return_if_fail (margin >= 0.f);
15333
15334   info = _clutter_actor_get_layout_info (self);
15335
15336   if (info->margin.left == margin)
15337     return;
15338
15339   info->margin.left = margin;
15340
15341   clutter_actor_queue_relayout (self);
15342
15343   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15344 }
15345
15346 /**
15347  * clutter_actor_get_margin_left:
15348  * @self: a #ClutterActor
15349  *
15350  * Retrieves the left margin of a #ClutterActor.
15351  *
15352  * Return value: the left margin
15353  *
15354  * Since: 1.10
15355  */
15356 gfloat
15357 clutter_actor_get_margin_left (ClutterActor *self)
15358 {
15359   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15360
15361   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15362 }
15363
15364 /**
15365  * clutter_actor_set_margin_right:
15366  * @self: a #ClutterActor
15367  * @margin: the right margin
15368  *
15369  * Sets the margin from the right of a #ClutterActor.
15370  *
15371  * Since: 1.10
15372  */
15373 void
15374 clutter_actor_set_margin_right (ClutterActor *self,
15375                                 gfloat        margin)
15376 {
15377   ClutterLayoutInfo *info;
15378
15379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15380   g_return_if_fail (margin >= 0.f);
15381
15382   info = _clutter_actor_get_layout_info (self);
15383
15384   if (info->margin.right == margin)
15385     return;
15386
15387   info->margin.right = margin;
15388
15389   clutter_actor_queue_relayout (self);
15390
15391   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15392 }
15393
15394 /**
15395  * clutter_actor_get_margin_right:
15396  * @self: a #ClutterActor
15397  *
15398  * Retrieves the right margin of a #ClutterActor.
15399  *
15400  * Return value: the right margin
15401  *
15402  * Since: 1.10
15403  */
15404 gfloat
15405 clutter_actor_get_margin_right (ClutterActor *self)
15406 {
15407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15408
15409   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15410 }
15411
15412 /**
15413  * clutter_actor_set_background_color:
15414  * @self: a #ClutterActor
15415  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15416  *  set color
15417  *
15418  * Sets the background color of a #ClutterActor.
15419  *
15420  * The background color will be used to cover the whole allocation of the
15421  * actor. The default background color of an actor is transparent.
15422  *
15423  * To check whether an actor has a background color, you can use the
15424  * #ClutterActor:background-color-set actor property.
15425  *
15426  * Since: 1.10
15427  */
15428 void
15429 clutter_actor_set_background_color (ClutterActor       *self,
15430                                     const ClutterColor *color)
15431 {
15432   ClutterActorPrivate *priv;
15433
15434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15435
15436   priv = self->priv;
15437
15438   if (color == NULL)
15439     {
15440       priv->bg_color_set = FALSE;
15441       g_object_notify_by_pspec (G_OBJECT (self),
15442                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15443       return;
15444     }
15445
15446   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15447     return;
15448
15449   priv->bg_color = *color;
15450   priv->bg_color_set = TRUE;
15451
15452   clutter_actor_queue_redraw (self);
15453
15454   g_object_notify_by_pspec (G_OBJECT (self),
15455                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15456   g_object_notify_by_pspec (G_OBJECT (self),
15457                             obj_props[PROP_BACKGROUND_COLOR]);
15458 }
15459
15460 /**
15461  * clutter_actor_get_background_color:
15462  * @self: a #ClutterActor
15463  * @color: (out caller-allocates): return location for a #ClutterColor
15464  *
15465  * Retrieves the color set using clutter_actor_set_background_color().
15466  *
15467  * Since: 1.10
15468  */
15469 void
15470 clutter_actor_get_background_color (ClutterActor *self,
15471                                     ClutterColor *color)
15472 {
15473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15474   g_return_if_fail (color != NULL);
15475
15476   *color = self->priv->bg_color;
15477 }
15478
15479 /**
15480  * clutter_actor_get_previous_sibling:
15481  * @self: a #ClutterActor
15482  *
15483  * Retrieves the sibling of @self that comes before it in the list
15484  * of children of @self's parent.
15485  *
15486  * The returned pointer is only valid until the scene graph changes; it
15487  * is not safe to modify the list of children of @self while iterating
15488  * it.
15489  *
15490  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15491  *
15492  * Since: 1.10
15493  */
15494 ClutterActor *
15495 clutter_actor_get_previous_sibling (ClutterActor *self)
15496 {
15497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15498
15499   return self->priv->prev_sibling;
15500 }
15501
15502 /**
15503  * clutter_actor_get_next_sibling:
15504  * @self: a #ClutterActor
15505  *
15506  * Retrieves the sibling of @self that comes after it in the list
15507  * of children of @self's parent.
15508  *
15509  * The returned pointer is only valid until the scene graph changes; it
15510  * is not safe to modify the list of children of @self while iterating
15511  * it.
15512  *
15513  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15514  *
15515  * Since: 1.10
15516  */
15517 ClutterActor *
15518 clutter_actor_get_next_sibling (ClutterActor *self)
15519 {
15520   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15521
15522   return self->priv->next_sibling;
15523 }
15524
15525 /**
15526  * clutter_actor_get_first_child:
15527  * @self: a #ClutterActor
15528  *
15529  * Retrieves the first child of @self.
15530  *
15531  * The returned pointer is only valid until the scene graph changes; it
15532  * is not safe to modify the list of children of @self while iterating
15533  * it.
15534  *
15535  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15536  *
15537  * Since: 1.10
15538  */
15539 ClutterActor *
15540 clutter_actor_get_first_child (ClutterActor *self)
15541 {
15542   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15543
15544   return self->priv->first_child;
15545 }
15546
15547 /**
15548  * clutter_actor_get_last_child:
15549  * @self: a #ClutterActor
15550  *
15551  * Retrieves the last child of @self.
15552  *
15553  * The returned pointer is only valid until the scene graph changes; it
15554  * is not safe to modify the list of children of @self while iterating
15555  * it.
15556  *
15557  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15558  *
15559  * Since: 1.10
15560  */
15561 ClutterActor *
15562 clutter_actor_get_last_child (ClutterActor *self)
15563 {
15564   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15565
15566   return self->priv->last_child;
15567 }
15568
15569 /* easy way to have properly named fields instead of the dummy ones
15570  * we use in the public structure
15571  */
15572 typedef struct _RealActorIter
15573 {
15574   ClutterActor *root;           /* dummy1 */
15575   ClutterActor *current;        /* dummy2 */
15576   gpointer padding_1;           /* dummy3 */
15577   gint age;                     /* dummy4 */
15578   gpointer padding_2;           /* dummy5 */
15579 } RealActorIter;
15580
15581 /**
15582  * clutter_actor_iter_init:
15583  * @iter: a #ClutterActorIter
15584  * @root: a #ClutterActor
15585  *
15586  * Initializes a #ClutterActorIter, which can then be used to iterate
15587  * efficiently over a section of the scene graph, and associates it
15588  * with @root.
15589  *
15590  * Modifying the scene graph section that contains @root will invalidate
15591  * the iterator.
15592  *
15593  * |[
15594  *   ClutterActorIter iter;
15595  *   ClutterActor *child;
15596  *
15597  *   clutter_actor_iter_init (&iter, container);
15598  *   while (clutter_actor_iter_next (&iter, &child))
15599  *     {
15600  *       /&ast; do something with child &ast;/
15601  *     }
15602  * ]|
15603  *
15604  * Since: 1.10
15605  */
15606 void
15607 clutter_actor_iter_init (ClutterActorIter *iter,
15608                          ClutterActor     *root)
15609 {
15610   RealActorIter *ri = (RealActorIter *) iter;
15611
15612   g_return_if_fail (iter != NULL);
15613   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15614
15615   ri->root = root;
15616   ri->current = NULL;
15617   ri->age = root->priv->age;
15618 }
15619
15620 /**
15621  * clutter_actor_iter_next:
15622  * @iter: a #ClutterActorIter
15623  * @child: (out): return location for a #ClutterActor
15624  *
15625  * Advances the @iter and retrieves the next child of the root #ClutterActor
15626  * that was used to initialize the #ClutterActorIterator.
15627  *
15628  * If the iterator can advance, this function returns %TRUE and sets the
15629  * @child argument.
15630  *
15631  * If the iterator cannot advance, this function returns %FALSE, and
15632  * the contents of @child are undefined.
15633  *
15634  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15635  *
15636  * Since: 1.10
15637  */
15638 gboolean
15639 clutter_actor_iter_next (ClutterActorIter  *iter,
15640                          ClutterActor     **child)
15641 {
15642   RealActorIter *ri = (RealActorIter *) iter;
15643
15644   g_return_val_if_fail (iter != NULL, FALSE);
15645   g_return_val_if_fail (ri->root != NULL, FALSE);
15646 #ifndef G_DISABLE_ASSERT
15647   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15648 #endif
15649
15650   if (ri->current == NULL)
15651     ri->current = ri->root->priv->first_child;
15652   else
15653     ri->current = ri->current->priv->next_sibling;
15654
15655   if (child != NULL)
15656     *child = ri->current;
15657
15658   return ri->current != NULL;
15659 }
15660
15661 /**
15662  * clutter_actor_iter_next:
15663  * @iter: a #ClutterActorIter
15664  * @child: (out): return location for a #ClutterActor
15665  *
15666  * Advances the @iter and retrieves the previous child of the root
15667  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15668  *
15669  * If the iterator can advance, this function returns %TRUE and sets the
15670  * @child argument.
15671  *
15672  * If the iterator cannot advance, this function returns %FALSE, and
15673  * the contents of @child are undefined.
15674  *
15675  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15676  *
15677  * Since: 1.10
15678  */
15679 gboolean
15680 clutter_actor_iter_prev (ClutterActorIter  *iter,
15681                          ClutterActor     **child)
15682 {
15683   RealActorIter *ri = (RealActorIter *) iter;
15684
15685   g_return_val_if_fail (iter != NULL, FALSE);
15686   g_return_val_if_fail (ri->root != NULL, FALSE);
15687 #ifndef G_DISABLE_ASSERT
15688   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15689 #endif
15690
15691   if (ri->current == NULL)
15692     ri->current = ri->root->priv->last_child;
15693   else
15694     ri->current = ri->current->priv->prev_sibling;
15695
15696   if (child != NULL)
15697     *child = ri->current;
15698
15699   return ri->current != NULL;
15700 }
15701
15702 /**
15703  * clutter_actor_iter_remove:
15704  * @iter: a #ClutterActorIter
15705  *
15706  * Safely removes the #ClutterActor currently pointer to by the iterator
15707  * from its parent.
15708  *
15709  * This function can only be called after clutter_actor_iter_next() or
15710  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15711  * than once for the same actor.
15712  *
15713  * This function will call clutter_actor_remove_child() internally.
15714  *
15715  * Since: 1.10
15716  */
15717 void
15718 clutter_actor_iter_remove (ClutterActorIter *iter)
15719 {
15720   RealActorIter *ri = (RealActorIter *) iter;
15721   ClutterActor *cur;
15722
15723   g_return_if_fail (iter != NULL);
15724   g_return_if_fail (ri->root != NULL);
15725 #ifndef G_DISABLE_ASSERT
15726   g_return_if_fail (ri->age == ri->root->priv->age);
15727 #endif
15728   g_return_if_fail (ri->current != NULL);
15729
15730   cur = ri->current;
15731
15732   if (cur != NULL)
15733     {
15734       ri->current = cur->priv->prev_sibling;
15735
15736       clutter_actor_remove_child_internal (ri->root, cur,
15737                                            REMOVE_CHILD_DEFAULT_FLAGS);
15738
15739       ri->age += 1;
15740     }
15741 }