actor: Avoid popping the easing state stack once too many
[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, 2011, 2012 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: The basic element of the scene graph 
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="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-subclassing">
217  *   <title>Implementing an actor</title>
218  *   <para>Careful consideration should be given when deciding to implement
219  *   a #ClutterActor sub-class. It is generally recommended to implement a
220  *   sub-class of #ClutterActor only for actors that should be used as leaf
221  *   nodes of a scene graph.</para>
222  *   <para>If your actor should be painted in a custom way, you should
223  *   override the #ClutterActor::paint signal class handler. You can either
224  *   opt to chain up to the parent class implementation or decide to fully
225  *   override the default paint implementation; Clutter will set up the
226  *   transformations and clip regions prior to emitting the #ClutterActor::paint
227  *   signal.</para>
228  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
229  *   #ClutterActorClass.get_preferred_height() virtual functions it is
230  *   possible to change or provide the preferred size of an actor; similarly,
231  *   by overriding the #ClutterActorClass.allocate() virtual function it is
232  *   possible to control the layout of the children of an actor. Make sure to
233  *   always chain up to the parent implementation of the
234  *   #ClutterActorClass.allocate() virtual function.</para>
235  *   <para>In general, it is strongly encouraged to use delegation and
236  *   composition instead of direct subclassing.</para>
237  * </refsect2>
238  *
239  * <refsect2 id="ClutterActor-script">
240  *   <title>ClutterActor custom properties for #ClutterScript</title>
241  *   <para>#ClutterActor defines a custom "rotation" property which
242  *   allows a short-hand description of the rotations to be applied
243  *   to an actor.</para>
244  *   <para>The syntax of the "rotation" property is the following:</para>
245  *   <informalexample>
246  *     <programlisting>
247  * "rotation" : [
248  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
249  * ]
250  *     </programlisting>
251  *   </informalexample>
252  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254  *   floating point value representing the rotation angle on the given axis,
255  *   in degrees.</para>
256  *   <para>The <emphasis>center</emphasis> array is optional, and if present
257  *   it must contain the center of rotation as described by two coordinates:
258  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
259  *   "z-axis".</para>
260  *   <para>#ClutterActor will also parse every positional and dimensional
261  *   property defined as a string through clutter_units_from_string(); you
262  *   should read the documentation for the #ClutterUnits parser format for
263  *   the valid units and syntax.</para>
264  * </refsect2>
265  *
266  * <refsect2 id="ClutterActor-animating">
267  *   <title>Custom animatable properties</title>
268  *   <para>#ClutterActor allows accessing properties of #ClutterAction
269  *   and #ClutterConstraint instances associated to an actor instance
270  *   for animation purposes.</para>
271  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272  *   property it is necessary to set the #ClutterActorMeta:name property on the
273  *   given action or constraint.</para>
274  *   <para>The property can be accessed using the following syntax:</para>
275  *   <informalexample>
276  *     <programlisting>
277  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
278  *     </programlisting>
279  *   </informalexample>
280  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281  *   <para>The <emphasis>section</emphasis> fragment can be one between
282  *   "actions", "constraints" and "effects".</para>
283  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284  *   action or constraint, as specified by the #ClutterActorMeta:name
285  *   property.</para>
286  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
287  *   action or constraint property to be animated.</para>
288  *   <para>The example below animates a #ClutterBindConstraint applied to an
289  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
291  *   its initial state is fully transparent and overlapping the actor to
292  *   which is bound to. </para>
293  *   <informalexample><programlisting>
294  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296  * clutter_actor_add_constraint (rect, constraint);
297  *
298  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300  * clutter_actor_add_constraint (rect, constraint);
301  *
302  * clutter_actor_set_reactive (rect, TRUE);
303  * clutter_actor_set_opacity (rect, 0);
304  *
305  * g_signal_connect (rect, "button-press-event",
306  *                   G_CALLBACK (on_button_press),
307  *                   NULL);
308  *   </programlisting></informalexample>
309  *   <para>On button press, the rectangle "slides" from behind the actor to
310  *   which is bound to, using the #ClutterBindConstraint:offset property and
311  *   the #ClutterActor:opacity property.</para>
312  *   <informalexample><programlisting>
313  * float new_offset = clutter_actor_get_width (origin) + h_padding;
314  *
315  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
316  *                        "opacity", 255,
317  *                        "@constraints.bind-x.offset", new_offset,
318  *                        NULL);
319  *   </programlisting></informalexample>
320  * </refsect2>
321  *
322  * <refsect2 id="ClutterActor-animatable-properties">
323  *   <title>Animatable properties</title>
324  *   <para>Certain properties on #ClutterActor are marked as "animatable";
325  *   these properties will be automatically tweened between the current
326  *   value and the new value when one is set.</para>
327  *   <para>For backward compatibility, animatable properties will only be
328  *   tweened if the easing duration is greater than 0, or if a new easing
329  *   state is set, for instance the following example:</para>
330  *   <informalexample><programlisting>
331  * clutter_actor_save_easing_state (actor);
332  * clutter_actor_set_position (actor, 200, 200);
333  * clutter_actor_restore_easing_state (actor);
334  *   </programlisting></informalexample>
335  *   <para>will tween the actor to the (200, 200) coordinates using the default
336  *   easing mode and duration of a new easing state. The example above is
337  *   equivalent to the following code:</para>
338  *   <informalexample><programlisting>
339  * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340  * clutter_actor_set_easing_duration (actor, 250);
341  * clutter_actor_set_position (actor, 200, 200);
342  * clutter_actor_restore_easing_state (actor);
343  *   </programlisting></informalexample>
344  *   <para>It is possible to nest easing states to tween animatable
345  *   properties using different modes and durations, for instance:</para>
346  *   <informalexample><programlisting>
347  * clutter_actor_save_easing_state (actor); /&ast; outer state &ast;/
348  *
349  * /&ast; set the duration of the animation to 2 seconds and change position &ast;/
350  * clutter_actor_set_easing_duration (actor, 2000);
351  * clutter_actor_set_position (actor, 0, 0);
352  *
353  * clutter_actor_save_easing_state (actor); /&ast; inner state &ast;/
354  *
355  * /&ast; set the duration of the animation to 5 seconds and change depth and opacity &ast;/
356  * clutter_actor_set_easing_duration (actor, 5000);
357  * clutter_actor_set_depth (actor, 200);
358  * clutter_actor_set_opacity (actor, 0);
359  *
360  * clutter_actor_restore_easing_state (actor);
361  *
362  * clutter_actor_restore_easing_state (actor);
363  *   </programlisting></informalexample>
364  * </refsect2>
365  */
366
367 /**
368  * CLUTTER_ACTOR_IS_MAPPED:
369  * @a: a #ClutterActor
370  *
371  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
372  *
373  * The mapped state is set when the actor is visible and all its parents up
374  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
375  *
376  * This check can be used to see if an actor is going to be painted, as only
377  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
378  *
379  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380  * not be checked directly; instead, the recommended usage is to connect a
381  * handler on the #GObject::notify signal for the #ClutterActor:mapped
382  * property of #ClutterActor, and check the presence of
383  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
384  *
385  * It is also important to note that Clutter may delay the changes of
386  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387  * limitations, or during the reparenting of an actor, to optimize
388  * unnecessary (and potentially expensive) state changes.
389  *
390  * Since: 0.2
391  */
392
393 /**
394  * CLUTTER_ACTOR_IS_REALIZED:
395  * @a: a #ClutterActor
396  *
397  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
398  *
399  * The realized state has an actor-dependant interpretation. If an
400  * actor wants to delay allocating resources until it is attached to a
401  * stage, it may use the realize state to do so. However it is
402  * perfectly acceptable for an actor to allocate Cogl resources before
403  * being realized because there is only one drawing context used by Clutter
404  * so any resources will work on any stage.  If an actor is mapped it
405  * must also be realized, but an actor can be realized and unmapped
406  * (this is so hiding an actor temporarily doesn't do an expensive
407  * unrealize/realize).
408  *
409  * To be realized an actor must be inside a stage, and all its parents
410  * must be realized.
411  *
412  * Since: 0.2
413  */
414
415 /**
416  * CLUTTER_ACTOR_IS_VISIBLE:
417  * @a: a #ClutterActor
418  *
419  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420  * Equivalent to the ClutterActor::visible object property.
421  *
422  * Note that an actor is only painted onscreen if it's mapped, which
423  * means it's visible, and all its parents are visible, and one of the
424  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
425  *
426  * Since: 0.2
427  */
428
429 /**
430  * CLUTTER_ACTOR_IS_REACTIVE:
431  * @a: a #ClutterActor
432  *
433  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
434  *
435  * Only reactive actors will receive event-related signals.
436  *
437  * Since: 0.6
438  */
439
440 #ifdef HAVE_CONFIG_H
441 #include "config.h"
442 #endif
443
444 #include <math.h>
445
446 #include <gobject/gvaluecollector.h>
447
448 #include <cogl/cogl.h>
449
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
452
453 #include "clutter-actor-private.h"
454
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
483
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
487
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
490
491 /* Internal enum used to control mapped state update.  This is a hint
492  * which indicates when to do something other than just enforce
493  * invariants.
494  */
495 typedef enum {
496   MAP_STATE_CHECK,           /* just enforce invariants. */
497   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498                               * used when about to unparent.
499                               */
500   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
501                               * used to set mapped on toplevels.
502                               */
503   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
504                               * used just before unmapping parent.
505                               */
506 } MapStateChange;
507
508 /* 3 entries should be a good compromise, few layout managers
509  * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
511
512 struct _ClutterActorPrivate
513 {
514   /* request mode */
515   ClutterRequestMode request_mode;
516
517   /* our cached size requests for different width / height */
518   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
520
521   /* An age of 0 means the entry is not set */
522   guint cached_height_age;
523   guint cached_width_age;
524
525   /* the bounding box of the actor, relative to the parent's
526    * allocation
527    */
528   ClutterActorBox allocation;
529   ClutterAllocationFlags allocation_flags;
530
531   /* clip, in actor coordinates */
532   cairo_rectangle_t clip;
533
534   /* the cached transformation matrix; see apply_transform() */
535   CoglMatrix transform;
536
537   guint8 opacity;
538   gint opacity_override;
539
540   ClutterOffscreenRedirect offscreen_redirect;
541
542   /* This is an internal effect used to implement the
543      offscreen-redirect property */
544   ClutterEffect *flatten_effect;
545
546   /* scene graph */
547   ClutterActor *parent;
548   ClutterActor *prev_sibling;
549   ClutterActor *next_sibling;
550   ClutterActor *first_child;
551   ClutterActor *last_child;
552
553   gint n_children;
554
555   /* tracks whenever the children of an actor are changed; the
556    * age is incremented by 1 whenever an actor is added or
557    * removed. the age is not incremented when the first or the
558    * last child pointers are changed, or when grandchildren of
559    * an actor are changed.
560    */
561   gint age;
562
563   gchar *name; /* a non-unique name, used for debugging */
564   guint32 id; /* unique id, used for backward compatibility */
565
566   gint32 pick_id; /* per-stage unique id, used for picking */
567
568   /* a back-pointer to the Pango context that we can use
569    * to create pre-configured PangoLayout
570    */
571   PangoContext *pango_context;
572
573   /* the text direction configured for this child - either by
574    * application code, or by the actor's parent
575    */
576   ClutterTextDirection text_direction;
577
578   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
579   gint internal_child;
580
581   /* meta classes */
582   ClutterMetaGroup *actions;
583   ClutterMetaGroup *constraints;
584   ClutterMetaGroup *effects;
585
586   /* delegate object used to allocate the children of this actor */
587   ClutterLayoutManager *layout_manager;
588
589   /* delegate object used to paint the contents of this actor */
590   ClutterContent *content;
591
592   ClutterContentGravity content_gravity;
593   ClutterScalingFilter min_filter;
594   ClutterScalingFilter mag_filter;
595
596   /* used when painting, to update the paint volume */
597   ClutterEffect *current_effect;
598
599   /* This is used to store an effect which needs to be redrawn. A
600      redraw can be queued to start from a particular effect. This is
601      used by parametrised effects that can cache an image of the
602      actor. If a parameter of the effect changes then it only needs to
603      redraw the cached image, not the actual actor. The pointer is
604      only valid if is_dirty == TRUE. If the pointer is NULL then the
605      whole actor is dirty. */
606   ClutterEffect *effect_to_redraw;
607
608   /* This is used when painting effects to implement the
609      clutter_actor_continue_paint() function. It points to the node in
610      the list of effects that is next in the chain */
611   const GList *next_effect_to_paint;
612
613   ClutterPaintVolume paint_volume;
614
615   /* NB: This volume isn't relative to this actor, it is in eye
616    * coordinates so that it can remain valid after the actor changes.
617    */
618   ClutterPaintVolume last_paint_volume;
619
620   ClutterStageQueueRedrawEntry *queue_redraw_entry;
621
622   ClutterColor bg_color;
623
624   /* bitfields */
625
626   /* fixed position and sizes */
627   guint position_set                : 1;
628   guint min_width_set               : 1;
629   guint min_height_set              : 1;
630   guint natural_width_set           : 1;
631   guint natural_height_set          : 1;
632   /* cached request is invalid (implies allocation is too) */
633   guint needs_width_request         : 1;
634   /* cached request is invalid (implies allocation is too) */
635   guint needs_height_request        : 1;
636   /* cached allocation is invalid (request has changed, probably) */
637   guint needs_allocation            : 1;
638   guint show_on_set_parent          : 1;
639   guint has_clip                    : 1;
640   guint clip_to_allocation          : 1;
641   guint enable_model_view_transform : 1;
642   guint enable_paint_unmapped       : 1;
643   guint has_pointer                 : 1;
644   guint propagated_one_redraw       : 1;
645   guint paint_volume_valid          : 1;
646   guint last_paint_volume_valid     : 1;
647   guint in_clone_paint              : 1;
648   guint transform_valid             : 1;
649   /* This is TRUE if anything has queued a redraw since we were last
650      painted. In this case effect_to_redraw will point to an effect
651      the redraw was queued from or it will be NULL if the redraw was
652      queued without an effect. */
653   guint is_dirty                    : 1;
654   guint bg_color_set                : 1;
655 };
656
657 enum
658 {
659   PROP_0,
660
661   PROP_NAME,
662
663   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664    * when set they force a size request, when gotten they
665    * get the allocation if the allocation is valid, and the
666    * request otherwise
667    */
668   PROP_X,
669   PROP_Y,
670   PROP_WIDTH,
671   PROP_HEIGHT,
672
673   /* Then the rest of these size-related properties are the "actual"
674    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675    */
676   PROP_FIXED_X,
677   PROP_FIXED_Y,
678
679   PROP_FIXED_POSITION_SET,
680
681   PROP_MIN_WIDTH,
682   PROP_MIN_WIDTH_SET,
683
684   PROP_MIN_HEIGHT,
685   PROP_MIN_HEIGHT_SET,
686
687   PROP_NATURAL_WIDTH,
688   PROP_NATURAL_WIDTH_SET,
689
690   PROP_NATURAL_HEIGHT,
691   PROP_NATURAL_HEIGHT_SET,
692
693   PROP_REQUEST_MODE,
694
695   /* Allocation properties are read-only */
696   PROP_ALLOCATION,
697
698   PROP_DEPTH,
699
700   PROP_CLIP,
701   PROP_HAS_CLIP,
702   PROP_CLIP_TO_ALLOCATION,
703
704   PROP_OPACITY,
705
706   PROP_OFFSCREEN_REDIRECT,
707
708   PROP_VISIBLE,
709   PROP_MAPPED,
710   PROP_REALIZED,
711   PROP_REACTIVE,
712
713   PROP_SCALE_X,
714   PROP_SCALE_Y,
715   PROP_SCALE_CENTER_X,
716   PROP_SCALE_CENTER_Y,
717   PROP_SCALE_GRAVITY,
718
719   PROP_ROTATION_ANGLE_X,
720   PROP_ROTATION_ANGLE_Y,
721   PROP_ROTATION_ANGLE_Z,
722   PROP_ROTATION_CENTER_X,
723   PROP_ROTATION_CENTER_Y,
724   PROP_ROTATION_CENTER_Z,
725   /* This property only makes sense for the z rotation because the
726      others would depend on the actor having a size along the
727      z-axis */
728   PROP_ROTATION_CENTER_Z_GRAVITY,
729
730   PROP_ANCHOR_X,
731   PROP_ANCHOR_Y,
732   PROP_ANCHOR_GRAVITY,
733
734   PROP_SHOW_ON_SET_PARENT,
735
736   PROP_TEXT_DIRECTION,
737   PROP_HAS_POINTER,
738
739   PROP_ACTIONS,
740   PROP_CONSTRAINTS,
741   PROP_EFFECT,
742
743   PROP_LAYOUT_MANAGER,
744
745   PROP_X_ALIGN,
746   PROP_Y_ALIGN,
747   PROP_MARGIN_TOP,
748   PROP_MARGIN_BOTTOM,
749   PROP_MARGIN_LEFT,
750   PROP_MARGIN_RIGHT,
751
752   PROP_BACKGROUND_COLOR,
753   PROP_BACKGROUND_COLOR_SET,
754
755   PROP_FIRST_CHILD,
756   PROP_LAST_CHILD,
757
758   PROP_CONTENT,
759   PROP_CONTENT_GRAVITY,
760   PROP_CONTENT_BOX,
761   PROP_MINIFICATION_FILTER,
762   PROP_MAGNIFICATION_FILTER,
763
764   PROP_LAST
765 };
766
767 static GParamSpec *obj_props[PROP_LAST];
768
769 enum
770 {
771   SHOW,
772   HIDE,
773   DESTROY,
774   PARENT_SET,
775   KEY_FOCUS_IN,
776   KEY_FOCUS_OUT,
777   PAINT,
778   PICK,
779   REALIZE,
780   UNREALIZE,
781   QUEUE_REDRAW,
782   QUEUE_RELAYOUT,
783   EVENT,
784   CAPTURED_EVENT,
785   BUTTON_PRESS_EVENT,
786   BUTTON_RELEASE_EVENT,
787   SCROLL_EVENT,
788   KEY_PRESS_EVENT,
789   KEY_RELEASE_EVENT,
790   MOTION_EVENT,
791   ENTER_EVENT,
792   LEAVE_EVENT,
793   ALLOCATION_CHANGED,
794
795   LAST_SIGNAL
796 };
797
798 static guint actor_signals[LAST_SIGNAL] = { 0, };
799
800 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
801 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
802 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
803 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
804
805 /* These setters are all static for now, maybe they should be in the
806  * public API, but they are perhaps obscure enough to leave only as
807  * properties
808  */
809 static void clutter_actor_set_min_width          (ClutterActor *self,
810                                                   gfloat        min_width);
811 static void clutter_actor_set_min_height         (ClutterActor *self,
812                                                   gfloat        min_height);
813 static void clutter_actor_set_natural_width      (ClutterActor *self,
814                                                   gfloat        natural_width);
815 static void clutter_actor_set_natural_height     (ClutterActor *self,
816                                                   gfloat        natural_height);
817 static void clutter_actor_set_min_width_set      (ClutterActor *self,
818                                                   gboolean      use_min_width);
819 static void clutter_actor_set_min_height_set     (ClutterActor *self,
820                                                   gboolean      use_min_height);
821 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
822                                                   gboolean  use_natural_width);
823 static void clutter_actor_set_natural_height_set (ClutterActor *self,
824                                                   gboolean  use_natural_height);
825 static void clutter_actor_update_map_state       (ClutterActor  *self,
826                                                   MapStateChange change);
827 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
828
829 /* Helper routines for managing anchor coords */
830 static void clutter_anchor_coord_get_units (ClutterActor      *self,
831                                             const AnchorCoord *coord,
832                                             gfloat            *x,
833                                             gfloat            *y,
834                                             gfloat            *z);
835 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
836                                             gfloat             x,
837                                             gfloat             y,
838                                             gfloat             z);
839
840 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
841 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
842                                                         ClutterGravity     gravity);
843
844 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
845
846 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
847
848 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
849                                                                ClutterActor *ancestor,
850                                                                CoglMatrix *matrix);
851
852 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
853
854 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
855
856 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
857                                                                 const ClutterColor *color);
858
859 static void on_layout_manager_changed (ClutterLayoutManager *manager,
860                                        ClutterActor         *self);
861
862 /* Helper macro which translates by the anchor coord, applies the
863    given transformation and then translates back */
864 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
865   gfloat _tx, _ty, _tz;                                                \
866   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
867   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
868   { _transform; }                                                      \
869   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
870
871 static GQuark quark_shader_data = 0;
872 static GQuark quark_actor_layout_info = 0;
873 static GQuark quark_actor_transform_info = 0;
874 static GQuark quark_actor_animation_info = 0;
875
876 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
877                          clutter_actor,
878                          G_TYPE_INITIALLY_UNOWNED,
879                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
880                                                 clutter_container_iface_init)
881                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
882                                                 clutter_scriptable_iface_init)
883                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
884                                                 clutter_animatable_iface_init)
885                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
886                                                 atk_implementor_iface_init));
887
888 /*< private >
889  * clutter_actor_get_debug_name:
890  * @actor: a #ClutterActor
891  *
892  * Retrieves a printable name of @actor for debugging messages
893  *
894  * Return value: a string with a printable name
895  */
896 const gchar *
897 _clutter_actor_get_debug_name (ClutterActor *actor)
898 {
899   return actor->priv->name != NULL ? actor->priv->name
900                                    : G_OBJECT_TYPE_NAME (actor);
901 }
902
903 #ifdef CLUTTER_ENABLE_DEBUG
904 /* XXX - this is for debugging only, remove once working (or leave
905  * in only in some debug mode). Should leave it for a little while
906  * until we're confident in the new map/realize/visible handling.
907  */
908 static inline void
909 clutter_actor_verify_map_state (ClutterActor *self)
910 {
911   ClutterActorPrivate *priv = self->priv;
912
913   if (CLUTTER_ACTOR_IS_REALIZED (self))
914     {
915       /* all bets are off during reparent when we're potentially realized,
916        * but should not be according to invariants
917        */
918       if (!CLUTTER_ACTOR_IN_REPARENT (self))
919         {
920           if (priv->parent == NULL)
921             {
922               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
923                 {
924                 }
925               else
926                 g_warning ("Realized non-toplevel actor '%s' should "
927                            "have a parent",
928                            _clutter_actor_get_debug_name (self));
929             }
930           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
931             {
932               g_warning ("Realized actor %s has an unrealized parent %s",
933                          _clutter_actor_get_debug_name (self),
934                          _clutter_actor_get_debug_name (priv->parent));
935             }
936         }
937     }
938
939   if (CLUTTER_ACTOR_IS_MAPPED (self))
940     {
941       if (!CLUTTER_ACTOR_IS_REALIZED (self))
942         g_warning ("Actor '%s' is mapped but not realized",
943                    _clutter_actor_get_debug_name (self));
944
945       /* remaining bets are off during reparent when we're potentially
946        * mapped, but should not be according to invariants
947        */
948       if (!CLUTTER_ACTOR_IN_REPARENT (self))
949         {
950           if (priv->parent == NULL)
951             {
952               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
953                 {
954                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
955                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
956                     {
957                       g_warning ("Toplevel actor '%s' is mapped "
958                                  "but not visible",
959                                  _clutter_actor_get_debug_name (self));
960                     }
961                 }
962               else
963                 {
964                   g_warning ("Mapped actor '%s' should have a parent",
965                              _clutter_actor_get_debug_name (self));
966                 }
967             }
968           else
969             {
970               ClutterActor *iter = self;
971
972               /* check for the enable_paint_unmapped flag on the actor
973                * and parents; if the flag is enabled at any point of this
974                * branch of the scene graph then all the later checks
975                * become pointless
976                */
977               while (iter != NULL)
978                 {
979                   if (iter->priv->enable_paint_unmapped)
980                     return;
981
982                   iter = iter->priv->parent;
983                 }
984
985               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
986                 {
987                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
988                              "is not visible",
989                              _clutter_actor_get_debug_name (self),
990                              _clutter_actor_get_debug_name (priv->parent));
991                 }
992
993               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
994                 {
995                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
996                              "is not realized",
997                              _clutter_actor_get_debug_name (self),
998                              _clutter_actor_get_debug_name (priv->parent));
999                 }
1000
1001               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1002                 {
1003                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1004                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1005                                "parent '%s' is not mapped",
1006                                _clutter_actor_get_debug_name (self),
1007                                _clutter_actor_get_debug_name (priv->parent));
1008                 }
1009             }
1010         }
1011     }
1012 }
1013
1014 #endif /* CLUTTER_ENABLE_DEBUG */
1015
1016 static void
1017 clutter_actor_set_mapped (ClutterActor *self,
1018                           gboolean      mapped)
1019 {
1020   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1021     return;
1022
1023   if (mapped)
1024     {
1025       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1026       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1027     }
1028   else
1029     {
1030       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1031       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1032     }
1033 }
1034
1035 /* this function updates the mapped and realized states according to
1036  * invariants, in the appropriate order.
1037  */
1038 static void
1039 clutter_actor_update_map_state (ClutterActor  *self,
1040                                 MapStateChange change)
1041 {
1042   gboolean was_mapped;
1043
1044   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1045
1046   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1047     {
1048       /* the mapped flag on top-level actors must be set by the
1049        * per-backend implementation because it might be asynchronous.
1050        *
1051        * That is, the MAPPED flag on toplevels currently tracks the X
1052        * server mapped-ness of the window, while the expected behavior
1053        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1054        * This creates some weird complexity by breaking the invariant
1055        * that if we're visible and all ancestors shown then we are
1056        * also mapped - instead, we are mapped if all ancestors
1057        * _possibly excepting_ the stage are mapped. The stage
1058        * will map/unmap for example when it is minimized or
1059        * moved to another workspace.
1060        *
1061        * So, the only invariant on the stage is that if visible it
1062        * should be realized, and that it has to be visible to be
1063        * mapped.
1064        */
1065       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1066         clutter_actor_realize (self);
1067
1068       switch (change)
1069         {
1070         case MAP_STATE_CHECK:
1071           break;
1072
1073         case MAP_STATE_MAKE_MAPPED:
1074           g_assert (!was_mapped);
1075           clutter_actor_set_mapped (self, TRUE);
1076           break;
1077
1078         case MAP_STATE_MAKE_UNMAPPED:
1079           g_assert (was_mapped);
1080           clutter_actor_set_mapped (self, FALSE);
1081           break;
1082
1083         case MAP_STATE_MAKE_UNREALIZED:
1084           /* we only use MAKE_UNREALIZED in unparent,
1085            * and unparenting a stage isn't possible.
1086            * If someone wants to just unrealize a stage
1087            * then clutter_actor_unrealize() doesn't
1088            * go through this codepath.
1089            */
1090           g_warning ("Trying to force unrealize stage is not allowed");
1091           break;
1092         }
1093
1094       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1095           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1096           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1097         {
1098           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1099                      "it is somehow still mapped",
1100                      _clutter_actor_get_debug_name (self));
1101         }
1102     }
1103   else
1104     {
1105       ClutterActorPrivate *priv = self->priv;
1106       ClutterActor *parent = priv->parent;
1107       gboolean should_be_mapped;
1108       gboolean may_be_realized;
1109       gboolean must_be_realized;
1110
1111       should_be_mapped = FALSE;
1112       may_be_realized = TRUE;
1113       must_be_realized = FALSE;
1114
1115       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1116         {
1117           may_be_realized = FALSE;
1118         }
1119       else
1120         {
1121           /* Maintain invariant that if parent is mapped, and we are
1122            * visible, then we are mapped ...  unless parent is a
1123            * stage, in which case we map regardless of parent's map
1124            * state but do require stage to be visible and realized.
1125            *
1126            * If parent is realized, that does not force us to be
1127            * realized; but if parent is unrealized, that does force
1128            * us to be unrealized.
1129            *
1130            * The reason we don't force children to realize with
1131            * parents is _clutter_actor_rerealize(); if we require that
1132            * a realized parent means children are realized, then to
1133            * unrealize an actor we would have to unrealize its
1134            * parents, which would end up meaning unrealizing and
1135            * hiding the entire stage. So we allow unrealizing a
1136            * child (as long as that child is not mapped) while that
1137            * child still has a realized parent.
1138            *
1139            * Also, if we unrealize from leaf nodes to root, and
1140            * realize from root to leaf, the invariants are never
1141            * violated if we allow children to be unrealized
1142            * while parents are realized.
1143            *
1144            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1145            * to force us to unmap, even though parent is still
1146            * mapped. This is because we're unmapping from leaf nodes
1147            * up to root nodes.
1148            */
1149           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1150               change != MAP_STATE_MAKE_UNMAPPED)
1151             {
1152               gboolean parent_is_visible_realized_toplevel;
1153
1154               parent_is_visible_realized_toplevel =
1155                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1156                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1157                  CLUTTER_ACTOR_IS_REALIZED (parent));
1158
1159               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1160                   parent_is_visible_realized_toplevel)
1161                 {
1162                   must_be_realized = TRUE;
1163                   should_be_mapped = TRUE;
1164                 }
1165             }
1166
1167           /* if the actor has been set to be painted even if unmapped
1168            * then we should map it and check for realization as well;
1169            * this is an override for the branch of the scene graph
1170            * which begins with this node
1171            */
1172           if (priv->enable_paint_unmapped)
1173             {
1174               if (priv->parent == NULL)
1175                 g_warning ("Attempting to map an unparented actor '%s'",
1176                            _clutter_actor_get_debug_name (self));
1177
1178               should_be_mapped = TRUE;
1179               must_be_realized = TRUE;
1180             }
1181
1182           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1183             may_be_realized = FALSE;
1184         }
1185
1186       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1187         {
1188           if (parent == NULL)
1189             g_warning ("Attempting to map a child that does not "
1190                        "meet the necessary invariants: the actor '%s' "
1191                        "has no parent",
1192                        _clutter_actor_get_debug_name (self));
1193           else
1194             g_warning ("Attempting to map a child that does not "
1195                        "meet the necessary invariants: the actor '%s' "
1196                        "is parented to an unmapped actor '%s'",
1197                        _clutter_actor_get_debug_name (self),
1198                        _clutter_actor_get_debug_name (priv->parent));
1199         }
1200
1201       /* If in reparent, we temporarily suspend unmap and unrealize.
1202        *
1203        * We want to go in the order "realize, map" and "unmap, unrealize"
1204        */
1205
1206       /* Unmap */
1207       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1208         clutter_actor_set_mapped (self, FALSE);
1209
1210       /* Realize */
1211       if (must_be_realized)
1212         clutter_actor_realize (self);
1213
1214       /* if we must be realized then we may be, presumably */
1215       g_assert (!(must_be_realized && !may_be_realized));
1216
1217       /* Unrealize */
1218       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1219         clutter_actor_unrealize_not_hiding (self);
1220
1221       /* Map */
1222       if (should_be_mapped)
1223         {
1224           if (!must_be_realized)
1225             g_warning ("Somehow we think actor '%s' should be mapped but "
1226                        "not realized, which isn't allowed",
1227                        _clutter_actor_get_debug_name (self));
1228
1229           /* realization is allowed to fail (though I don't know what
1230            * an app is supposed to do about that - shouldn't it just
1231            * be a g_error? anyway, we have to avoid mapping if this
1232            * happens)
1233            */
1234           if (CLUTTER_ACTOR_IS_REALIZED (self))
1235             clutter_actor_set_mapped (self, TRUE);
1236         }
1237     }
1238
1239 #ifdef CLUTTER_ENABLE_DEBUG
1240   /* check all invariants were kept */
1241   clutter_actor_verify_map_state (self);
1242 #endif
1243 }
1244
1245 static void
1246 clutter_actor_real_map (ClutterActor *self)
1247 {
1248   ClutterActorPrivate *priv = self->priv;
1249   ClutterActor *stage, *iter;
1250
1251   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1252
1253   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1254                 _clutter_actor_get_debug_name (self));
1255
1256   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1257
1258   stage = _clutter_actor_get_stage_internal (self);
1259   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1260
1261   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1262                 priv->pick_id,
1263                 _clutter_actor_get_debug_name (self));
1264
1265   /* notify on parent mapped before potentially mapping
1266    * children, so apps see a top-down notification.
1267    */
1268   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1269
1270   for (iter = self->priv->first_child;
1271        iter != NULL;
1272        iter = iter->priv->next_sibling)
1273     {
1274       clutter_actor_map (iter);
1275     }
1276 }
1277
1278 /**
1279  * clutter_actor_map:
1280  * @self: A #ClutterActor
1281  *
1282  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1283  * and realizes its children if they are visible. Does nothing if the
1284  * actor is not visible.
1285  *
1286  * Calling this function is strongly disencouraged: the default
1287  * implementation of #ClutterActorClass.map() will map all the children
1288  * of an actor when mapping its parent.
1289  *
1290  * When overriding map, it is mandatory to chain up to the parent
1291  * implementation.
1292  *
1293  * Since: 1.0
1294  */
1295 void
1296 clutter_actor_map (ClutterActor *self)
1297 {
1298   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1299
1300   if (CLUTTER_ACTOR_IS_MAPPED (self))
1301     return;
1302
1303   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1304     return;
1305
1306   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1307 }
1308
1309 static void
1310 clutter_actor_real_unmap (ClutterActor *self)
1311 {
1312   ClutterActorPrivate *priv = self->priv;
1313   ClutterActor *iter;
1314
1315   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1316
1317   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1318                 _clutter_actor_get_debug_name (self));
1319
1320   for (iter = self->priv->first_child;
1321        iter != NULL;
1322        iter = iter->priv->next_sibling)
1323     {
1324       clutter_actor_unmap (iter);
1325     }
1326
1327   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1328
1329   /* clear the contents of the last paint volume, so that hiding + moving +
1330    * showing will not result in the wrong area being repainted
1331    */
1332   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1333   priv->last_paint_volume_valid = TRUE;
1334
1335   /* notify on parent mapped after potentially unmapping
1336    * children, so apps see a bottom-up notification.
1337    */
1338   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1339
1340   /* relinquish keyboard focus if we were unmapped while owning it */
1341   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1342     {
1343       ClutterStage *stage;
1344
1345       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1346
1347       if (stage != NULL)
1348         _clutter_stage_release_pick_id (stage, priv->pick_id);
1349
1350       priv->pick_id = -1;
1351
1352       if (stage != NULL &&
1353           clutter_stage_get_key_focus (stage) == self)
1354         {
1355           clutter_stage_set_key_focus (stage, NULL);
1356         }
1357     }
1358 }
1359
1360 /**
1361  * clutter_actor_unmap:
1362  * @self: A #ClutterActor
1363  *
1364  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1365  * unmaps its children if they were mapped.
1366  *
1367  * Calling this function is not encouraged: the default #ClutterActor
1368  * implementation of #ClutterActorClass.unmap() will also unmap any
1369  * eventual children by default when their parent is unmapped.
1370  *
1371  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1372  * chain up to the parent implementation.
1373  *
1374  * <note>It is important to note that the implementation of the
1375  * #ClutterActorClass.unmap() virtual function may be called after
1376  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1377  * implementation, but it is guaranteed to be called before the
1378  * #GObjectClass.finalize() implementation.</note>
1379  *
1380  * Since: 1.0
1381  */
1382 void
1383 clutter_actor_unmap (ClutterActor *self)
1384 {
1385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1386
1387   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1388     return;
1389
1390   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1391 }
1392
1393 static void
1394 clutter_actor_real_show (ClutterActor *self)
1395 {
1396   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1397     {
1398       ClutterActorPrivate *priv = self->priv;
1399
1400       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1401
1402       /* we notify on the "visible" flag in the clutter_actor_show()
1403        * wrapper so the entire show signal emission completes first
1404        * (?)
1405        */
1406       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1407
1408       /* we queue a relayout unless the actor is inside a
1409        * container that explicitly told us not to
1410        */
1411       if (priv->parent != NULL &&
1412           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1413         {
1414           /* While an actor is hidden the parent may not have
1415            * allocated/requested so we need to start from scratch
1416            * and avoid the short-circuiting in
1417            * clutter_actor_queue_relayout().
1418            */
1419           priv->needs_width_request  = FALSE;
1420           priv->needs_height_request = FALSE;
1421           priv->needs_allocation     = FALSE;
1422           clutter_actor_queue_relayout (self);
1423         }
1424     }
1425 }
1426
1427 static inline void
1428 set_show_on_set_parent (ClutterActor *self,
1429                         gboolean      set_show)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432
1433   set_show = !!set_show;
1434
1435   if (priv->show_on_set_parent == set_show)
1436     return;
1437
1438   if (priv->parent == NULL)
1439     {
1440       priv->show_on_set_parent = set_show;
1441       g_object_notify_by_pspec (G_OBJECT (self),
1442                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1443     }
1444 }
1445
1446 /**
1447  * clutter_actor_show:
1448  * @self: A #ClutterActor
1449  *
1450  * Flags an actor to be displayed. An actor that isn't shown will not
1451  * be rendered on the stage.
1452  *
1453  * Actors are visible by default.
1454  *
1455  * If this function is called on an actor without a parent, the
1456  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1457  * effect.
1458  */
1459 void
1460 clutter_actor_show (ClutterActor *self)
1461 {
1462   ClutterActorPrivate *priv;
1463
1464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1465
1466   /* simple optimization */
1467   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1468     {
1469       /* we still need to set the :show-on-set-parent property, in
1470        * case show() is called on an unparented actor
1471        */
1472       set_show_on_set_parent (self, TRUE);
1473       return;
1474     }
1475
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477   clutter_actor_verify_map_state (self);
1478 #endif
1479
1480   priv = self->priv;
1481
1482   g_object_freeze_notify (G_OBJECT (self));
1483
1484   set_show_on_set_parent (self, TRUE);
1485
1486   g_signal_emit (self, actor_signals[SHOW], 0);
1487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1488
1489   if (priv->parent != NULL)
1490     clutter_actor_queue_redraw (priv->parent);
1491
1492   g_object_thaw_notify (G_OBJECT (self));
1493 }
1494
1495 /**
1496  * clutter_actor_show_all:
1497  * @self: a #ClutterActor
1498  *
1499  * Calls clutter_actor_show() on all children of an actor (if any).
1500  *
1501  * Since: 0.2
1502  *
1503  * Deprecated: 1.10: Actors are visible by default
1504  */
1505 void
1506 clutter_actor_show_all (ClutterActor *self)
1507 {
1508   ClutterActorClass *klass;
1509
1510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1511
1512   klass = CLUTTER_ACTOR_GET_CLASS (self);
1513   if (klass->show_all)
1514     klass->show_all (self);
1515 }
1516
1517 static void
1518 clutter_actor_real_hide (ClutterActor *self)
1519 {
1520   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1521     {
1522       ClutterActorPrivate *priv = self->priv;
1523
1524       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1525
1526       /* we notify on the "visible" flag in the clutter_actor_hide()
1527        * wrapper so the entire hide signal emission completes first
1528        * (?)
1529        */
1530       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1531
1532       /* we queue a relayout unless the actor is inside a
1533        * container that explicitly told us not to
1534        */
1535       if (priv->parent != NULL &&
1536           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537         clutter_actor_queue_relayout (priv->parent);
1538     }
1539 }
1540
1541 /**
1542  * clutter_actor_hide:
1543  * @self: A #ClutterActor
1544  *
1545  * Flags an actor to be hidden. A hidden actor will not be
1546  * rendered on the stage.
1547  *
1548  * Actors are visible by default.
1549  *
1550  * If this function is called on an actor without a parent, the
1551  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1552  * as a side-effect.
1553  */
1554 void
1555 clutter_actor_hide (ClutterActor *self)
1556 {
1557   ClutterActorPrivate *priv;
1558
1559   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1560
1561   /* simple optimization */
1562   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1563     {
1564       /* we still need to set the :show-on-set-parent property, in
1565        * case hide() is called on an unparented actor
1566        */
1567       set_show_on_set_parent (self, FALSE);
1568       return;
1569     }
1570
1571 #ifdef CLUTTER_ENABLE_DEBUG
1572   clutter_actor_verify_map_state (self);
1573 #endif
1574
1575   priv = self->priv;
1576
1577   g_object_freeze_notify (G_OBJECT (self));
1578
1579   set_show_on_set_parent (self, FALSE);
1580
1581   g_signal_emit (self, actor_signals[HIDE], 0);
1582   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1583
1584   if (priv->parent != NULL)
1585     clutter_actor_queue_redraw (priv->parent);
1586
1587   g_object_thaw_notify (G_OBJECT (self));
1588 }
1589
1590 /**
1591  * clutter_actor_hide_all:
1592  * @self: a #ClutterActor
1593  *
1594  * Calls clutter_actor_hide() on all child actors (if any).
1595  *
1596  * Since: 0.2
1597  *
1598  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1599  *   prevent its children from being painted as well.
1600  */
1601 void
1602 clutter_actor_hide_all (ClutterActor *self)
1603 {
1604   ClutterActorClass *klass;
1605
1606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1607
1608   klass = CLUTTER_ACTOR_GET_CLASS (self);
1609   if (klass->hide_all)
1610     klass->hide_all (self);
1611 }
1612
1613 /**
1614  * clutter_actor_realize:
1615  * @self: A #ClutterActor
1616  *
1617  * Realization informs the actor that it is attached to a stage. It
1618  * can use this to allocate resources if it wanted to delay allocation
1619  * until it would be rendered. However it is perfectly acceptable for
1620  * an actor to create resources before being realized because Clutter
1621  * only ever has a single rendering context so that actor is free to
1622  * be moved from one stage to another.
1623  *
1624  * This function does nothing if the actor is already realized.
1625  *
1626  * Because a realized actor must have realized parent actors, calling
1627  * clutter_actor_realize() will also realize all parents of the actor.
1628  *
1629  * This function does not realize child actors, except in the special
1630  * case that realizing the stage, when the stage is visible, will
1631  * suddenly map (and thus realize) the children of the stage.
1632  **/
1633 void
1634 clutter_actor_realize (ClutterActor *self)
1635 {
1636   ClutterActorPrivate *priv;
1637
1638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1639
1640   priv = self->priv;
1641
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643   clutter_actor_verify_map_state (self);
1644 #endif
1645
1646   if (CLUTTER_ACTOR_IS_REALIZED (self))
1647     return;
1648
1649   /* To be realized, our parent actors must be realized first.
1650    * This will only succeed if we're inside a toplevel.
1651    */
1652   if (priv->parent != NULL)
1653     clutter_actor_realize (priv->parent);
1654
1655   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1656     {
1657       /* toplevels can be realized at any time */
1658     }
1659   else
1660     {
1661       /* "Fail" the realization if parent is missing or unrealized;
1662        * this should really be a g_warning() not some kind of runtime
1663        * failure; how can an app possibly recover? Instead it's a bug
1664        * in the app and the app should get an explanatory warning so
1665        * someone can fix it. But for now it's too hard to fix this
1666        * because e.g. ClutterTexture needs reworking.
1667        */
1668       if (priv->parent == NULL ||
1669           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1670         return;
1671     }
1672
1673   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1674
1675   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1676   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1677
1678   g_signal_emit (self, actor_signals[REALIZE], 0);
1679
1680   /* Stage actor is allowed to unset the realized flag again in its
1681    * default signal handler, though that is a pathological situation.
1682    */
1683
1684   /* If realization "failed" we'll have to update child state. */
1685   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1686 }
1687
1688 static void
1689 clutter_actor_real_unrealize (ClutterActor *self)
1690 {
1691   /* we must be unmapped (implying our children are also unmapped) */
1692   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1693 }
1694
1695 /**
1696  * clutter_actor_unrealize:
1697  * @self: A #ClutterActor
1698  *
1699  * Unrealization informs the actor that it may be being destroyed or
1700  * moved to another stage. The actor may want to destroy any
1701  * underlying graphics resources at this point. However it is
1702  * perfectly acceptable for it to retain the resources until the actor
1703  * is destroyed because Clutter only ever uses a single rendering
1704  * context and all of the graphics resources are valid on any stage.
1705  *
1706  * Because mapped actors must be realized, actors may not be
1707  * unrealized if they are mapped. This function hides the actor to be
1708  * sure it isn't mapped, an application-visible side effect that you
1709  * may not be expecting.
1710  *
1711  * This function should not be called by application code.
1712  */
1713 void
1714 clutter_actor_unrealize (ClutterActor *self)
1715 {
1716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1717   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1718
1719 /* This function should not really be in the public API, because
1720  * there isn't a good reason to call it. ClutterActor will already
1721  * unrealize things for you when it's important to do so.
1722  *
1723  * If you were using clutter_actor_unrealize() in a dispose
1724  * implementation, then don't, just chain up to ClutterActor's
1725  * dispose.
1726  *
1727  * If you were using clutter_actor_unrealize() to implement
1728  * unrealizing children of your container, then don't, ClutterActor
1729  * will already take care of that.
1730  *
1731  * If you were using clutter_actor_unrealize() to re-realize to
1732  * create your resources in a different way, then use
1733  * _clutter_actor_rerealize() (inside Clutter) or just call your
1734  * code that recreates your resources directly (outside Clutter).
1735  */
1736
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738   clutter_actor_verify_map_state (self);
1739 #endif
1740
1741   clutter_actor_hide (self);
1742
1743   clutter_actor_unrealize_not_hiding (self);
1744 }
1745
1746 static ClutterActorTraverseVisitFlags
1747 unrealize_actor_before_children_cb (ClutterActor *self,
1748                                     int depth,
1749                                     void *user_data)
1750 {
1751   /* If an actor is already unrealized we know its children have also
1752    * already been unrealized... */
1753   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1754     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1755
1756   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1757
1758   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1759 }
1760
1761 static ClutterActorTraverseVisitFlags
1762 unrealize_actor_after_children_cb (ClutterActor *self,
1763                                    int depth,
1764                                    void *user_data)
1765 {
1766   /* We want to unset the realized flag only _after_
1767    * child actors are unrealized, to maintain invariants.
1768    */
1769   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1770   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1771   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1772 }
1773
1774 /*
1775  * clutter_actor_unrealize_not_hiding:
1776  * @self: A #ClutterActor
1777  *
1778  * Unrealization informs the actor that it may be being destroyed or
1779  * moved to another stage. The actor may want to destroy any
1780  * underlying graphics resources at this point. However it is
1781  * perfectly acceptable for it to retain the resources until the actor
1782  * is destroyed because Clutter only ever uses a single rendering
1783  * context and all of the graphics resources are valid on any stage.
1784  *
1785  * Because mapped actors must be realized, actors may not be
1786  * unrealized if they are mapped. You must hide the actor or one of
1787  * its parents before attempting to unrealize.
1788  *
1789  * This function is separate from clutter_actor_unrealize() because it
1790  * does not automatically hide the actor.
1791  * Actors need not be hidden to be unrealized, they just need to
1792  * be unmapped. In fact we don't want to mess up the application's
1793  * setting of the "visible" flag, so hiding is very undesirable.
1794  *
1795  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1796  * backward compatibility.
1797  */
1798 static void
1799 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1800 {
1801   _clutter_actor_traverse (self,
1802                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1803                            unrealize_actor_before_children_cb,
1804                            unrealize_actor_after_children_cb,
1805                            NULL);
1806 }
1807
1808 /*
1809  * _clutter_actor_rerealize:
1810  * @self: A #ClutterActor
1811  * @callback: Function to call while unrealized
1812  * @data: data for callback
1813  *
1814  * If an actor is already unrealized, this just calls the callback.
1815  *
1816  * If it is realized, it unrealizes temporarily, calls the callback,
1817  * and then re-realizes the actor.
1818  *
1819  * As a side effect, leaves all children of the actor unrealized if
1820  * the actor was realized but not showing.  This is because when we
1821  * unrealize the actor temporarily we must unrealize its children
1822  * (e.g. children of a stage can't be realized if stage window is
1823  * gone). And we aren't clever enough to save the realization state of
1824  * all children. In most cases this should not matter, because
1825  * the children will automatically realize when they next become mapped.
1826  */
1827 void
1828 _clutter_actor_rerealize (ClutterActor    *self,
1829                           ClutterCallback  callback,
1830                           void            *data)
1831 {
1832   gboolean was_mapped;
1833   gboolean was_showing;
1834   gboolean was_realized;
1835
1836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1837
1838 #ifdef CLUTTER_ENABLE_DEBUG
1839   clutter_actor_verify_map_state (self);
1840 #endif
1841
1842   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1843   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1844   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1845
1846   /* Must be unmapped to unrealize. Note we only have to hide this
1847    * actor if it was mapped (if all parents were showing).  If actor
1848    * is merely visible (but not mapped), then that's fine, we can
1849    * leave it visible.
1850    */
1851   if (was_mapped)
1852     clutter_actor_hide (self);
1853
1854   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1855
1856   /* unrealize self and all children */
1857   clutter_actor_unrealize_not_hiding (self);
1858
1859   if (callback != NULL)
1860     {
1861       (* callback) (self, data);
1862     }
1863
1864   if (was_showing)
1865     clutter_actor_show (self); /* will realize only if mapping implies it */
1866   else if (was_realized)
1867     clutter_actor_realize (self); /* realize self and all parents */
1868 }
1869
1870 static void
1871 clutter_actor_real_pick (ClutterActor       *self,
1872                          const ClutterColor *color)
1873 {
1874   /* the default implementation is just to paint a rectangle
1875    * with the same size of the actor using the passed color
1876    */
1877   if (clutter_actor_should_pick_paint (self))
1878     {
1879       ClutterActorBox box = { 0, };
1880       float width, height;
1881
1882       clutter_actor_get_allocation_box (self, &box);
1883
1884       width = box.x2 - box.x1;
1885       height = box.y2 - box.y1;
1886
1887       cogl_set_source_color4ub (color->red,
1888                                 color->green,
1889                                 color->blue,
1890                                 color->alpha);
1891
1892       cogl_rectangle (0, 0, width, height);
1893     }
1894
1895   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1896    * with existing container classes that override the pick() virtual
1897    * and chain up to the default implementation - otherwise we'll end up
1898    * painting our children twice.
1899    *
1900    * this has to go away for 2.0; hopefully along the pick() itself.
1901    */
1902   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1903     {
1904       ClutterActor *iter;
1905
1906       for (iter = self->priv->first_child;
1907            iter != NULL;
1908            iter = iter->priv->next_sibling)
1909         clutter_actor_paint (iter);
1910     }
1911 }
1912
1913 /**
1914  * clutter_actor_should_pick_paint:
1915  * @self: A #ClutterActor
1916  *
1917  * Should be called inside the implementation of the
1918  * #ClutterActor::pick virtual function in order to check whether
1919  * the actor should paint itself in pick mode or not.
1920  *
1921  * This function should never be called directly by applications.
1922  *
1923  * Return value: %TRUE if the actor should paint its silhouette,
1924  *   %FALSE otherwise
1925  */
1926 gboolean
1927 clutter_actor_should_pick_paint (ClutterActor *self)
1928 {
1929   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1930
1931   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1932       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1933        CLUTTER_ACTOR_IS_REACTIVE (self)))
1934     return TRUE;
1935
1936   return FALSE;
1937 }
1938
1939 static void
1940 clutter_actor_real_get_preferred_width (ClutterActor *self,
1941                                         gfloat        for_height,
1942                                         gfloat       *min_width_p,
1943                                         gfloat       *natural_width_p)
1944 {
1945   ClutterActorPrivate *priv = self->priv;
1946
1947   if (priv->n_children != 0 &&
1948       priv->layout_manager != NULL)
1949     {
1950       ClutterContainer *container = CLUTTER_CONTAINER (self);
1951
1952       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1953                     "for the preferred width",
1954                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1955                     priv->layout_manager);
1956
1957       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1958                                                   container,
1959                                                   for_height,
1960                                                   min_width_p,
1961                                                   natural_width_p);
1962
1963       return;
1964     }
1965
1966   /* Default implementation is always 0x0, usually an actor
1967    * using this default is relying on someone to set the
1968    * request manually
1969    */
1970   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1971
1972   if (min_width_p)
1973     *min_width_p = 0;
1974
1975   if (natural_width_p)
1976     *natural_width_p = 0;
1977 }
1978
1979 static void
1980 clutter_actor_real_get_preferred_height (ClutterActor *self,
1981                                          gfloat        for_width,
1982                                          gfloat       *min_height_p,
1983                                          gfloat       *natural_height_p)
1984 {
1985   ClutterActorPrivate *priv = self->priv;
1986
1987   if (priv->n_children != 0 &&
1988       priv->layout_manager != NULL)
1989     {
1990       ClutterContainer *container = CLUTTER_CONTAINER (self);
1991
1992       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1993                     "for the preferred height",
1994                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1995                     priv->layout_manager);
1996
1997       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1998                                                    container,
1999                                                    for_width,
2000                                                    min_height_p,
2001                                                    natural_height_p);
2002
2003       return;
2004     }
2005   /* Default implementation is always 0x0, usually an actor
2006    * using this default is relying on someone to set the
2007    * request manually
2008    */
2009   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2010
2011   if (min_height_p)
2012     *min_height_p = 0;
2013
2014   if (natural_height_p)
2015     *natural_height_p = 0;
2016 }
2017
2018 static void
2019 clutter_actor_store_old_geometry (ClutterActor    *self,
2020                                   ClutterActorBox *box)
2021 {
2022   *box = self->priv->allocation;
2023 }
2024
2025 static inline void
2026 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2027                                           const ClutterActorBox *old)
2028 {
2029   ClutterActorPrivate *priv = self->priv;
2030   GObject *obj = G_OBJECT (self);
2031
2032   g_object_freeze_notify (obj);
2033
2034   /* to avoid excessive requisition or allocation cycles we
2035    * use the cached values.
2036    *
2037    * - if we don't have an allocation we assume that we need
2038    *   to notify anyway
2039    * - if we don't have a width or a height request we notify
2040    *   width and height
2041    * - if we have a valid allocation then we check the old
2042    *   bounding box with the current allocation and we notify
2043    *   the changes
2044    */
2045   if (priv->needs_allocation)
2046     {
2047       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2048       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2049       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2050       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2051     }
2052   else if (priv->needs_width_request || priv->needs_height_request)
2053     {
2054       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2055       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2056     }
2057   else
2058     {
2059       gfloat x, y;
2060       gfloat width, height;
2061
2062       x = priv->allocation.x1;
2063       y = priv->allocation.y1;
2064       width = priv->allocation.x2 - priv->allocation.x1;
2065       height = priv->allocation.y2 - priv->allocation.y1;
2066
2067       if (x != old->x1)
2068         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2069
2070       if (y != old->y1)
2071         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2072
2073       if (width != (old->x2 - old->x1))
2074         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2075
2076       if (height != (old->y2 - old->y1))
2077         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2078     }
2079
2080   g_object_thaw_notify (obj);
2081 }
2082
2083 /*< private >
2084  * clutter_actor_set_allocation_internal:
2085  * @self: a #ClutterActor
2086  * @box: a #ClutterActorBox
2087  * @flags: allocation flags
2088  *
2089  * Stores the allocation of @self.
2090  *
2091  * This function only performs basic storage and property notification.
2092  *
2093  * This function should be called by clutter_actor_set_allocation()
2094  * and by the default implementation of #ClutterActorClass.allocate().
2095  *
2096  * Return value: %TRUE if the allocation of the #ClutterActor has been
2097  *   changed, and %FALSE otherwise
2098  */
2099 static inline gboolean
2100 clutter_actor_set_allocation_internal (ClutterActor           *self,
2101                                        const ClutterActorBox  *box,
2102                                        ClutterAllocationFlags  flags)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105   GObject *obj;
2106   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2107   gboolean flags_changed;
2108   gboolean retval;
2109   ClutterActorBox old_alloc = { 0, };
2110
2111   obj = G_OBJECT (self);
2112
2113   g_object_freeze_notify (obj);
2114
2115   clutter_actor_store_old_geometry (self, &old_alloc);
2116
2117   x1_changed = priv->allocation.x1 != box->x1;
2118   y1_changed = priv->allocation.y1 != box->y1;
2119   x2_changed = priv->allocation.x2 != box->x2;
2120   y2_changed = priv->allocation.y2 != box->y2;
2121
2122   flags_changed = priv->allocation_flags != flags;
2123
2124   priv->allocation = *box;
2125   priv->allocation_flags = flags;
2126
2127   /* allocation is authoritative */
2128   priv->needs_width_request = FALSE;
2129   priv->needs_height_request = FALSE;
2130   priv->needs_allocation = FALSE;
2131
2132   if (x1_changed || y1_changed ||
2133       x2_changed || y2_changed ||
2134       flags_changed)
2135     {
2136       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2137                     _clutter_actor_get_debug_name (self));
2138
2139       priv->transform_valid = FALSE;
2140
2141       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2142
2143       /* if the allocation changes, so does the content box */
2144       if (priv->content != NULL)
2145         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2146
2147       retval = TRUE;
2148     }
2149   else
2150     retval = FALSE;
2151
2152   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2153
2154   g_object_thaw_notify (obj);
2155
2156   return retval;
2157 }
2158
2159 static void clutter_actor_real_allocate (ClutterActor           *self,
2160                                          const ClutterActorBox  *box,
2161                                          ClutterAllocationFlags  flags);
2162
2163 static inline void
2164 clutter_actor_maybe_layout_children (ClutterActor           *self,
2165                                      const ClutterActorBox  *allocation,
2166                                      ClutterAllocationFlags  flags)
2167 {
2168   ClutterActorPrivate *priv = self->priv;
2169
2170   /* this is going to be a bit hard to follow, so let's put an explanation
2171    * here.
2172    *
2173    * we want ClutterActor to have a default layout manager if the actor was
2174    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2175    *
2176    * we also want any subclass of ClutterActor that does not override the
2177    * ::allocate() virtual function to delegate to a layout manager.
2178    *
2179    * finally, we want to allow people subclassing ClutterActor and overriding
2180    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2181    *
2182    * on the other hand, we want existing actor subclasses overriding the
2183    * ::allocate() virtual function and chaining up to the parent's
2184    * implementation to continue working without allocating their children
2185    * twice, or without entering an allocation loop.
2186    *
2187    * for the first two points, we check if the class of the actor is
2188    * overridding the ::allocate() virtual function; if it isn't, then we
2189    * follow through with checking whether we have children and a layout
2190    * manager, and eventually calling clutter_layout_manager_allocate().
2191    *
2192    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2193    * allocation flags that we got passed, and if it is present, we continue
2194    * with the check above.
2195    *
2196    * if neither of these two checks yields a positive result, we just
2197    * assume that the ::allocate() virtual function that resulted in this
2198    * function being called will also allocate the children of the actor.
2199    */
2200
2201   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2202     goto check_layout;
2203
2204   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2205     goto check_layout;
2206
2207   return;
2208
2209 check_layout:
2210   if (priv->n_children != 0 &&
2211       priv->layout_manager != NULL)
2212     {
2213       ClutterContainer *container = CLUTTER_CONTAINER (self);
2214       ClutterAllocationFlags children_flags;
2215       ClutterActorBox children_box;
2216
2217       /* normalize the box passed to the layout manager */
2218       children_box.x1 = children_box.y1 = 0.f;
2219       children_box.x2 = (allocation->x2 - allocation->x1);
2220       children_box.y2 = (allocation->y2 - allocation->y1);
2221
2222       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2223        * the actor's children, since it refers only to the current
2224        * actor's allocation.
2225        */
2226       children_flags = flags;
2227       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2228
2229       CLUTTER_NOTE (LAYOUT,
2230                     "Allocating %d children of %s "
2231                     "at { %.2f, %.2f - %.2f x %.2f } "
2232                     "using %s",
2233                     priv->n_children,
2234                     _clutter_actor_get_debug_name (self),
2235                     allocation->x1,
2236                     allocation->y1,
2237                     (allocation->x2 - allocation->x1),
2238                     (allocation->y2 - allocation->y1),
2239                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2240
2241       clutter_layout_manager_allocate (priv->layout_manager,
2242                                        container,
2243                                        &children_box,
2244                                        children_flags);
2245     }
2246 }
2247
2248 static void
2249 clutter_actor_real_allocate (ClutterActor           *self,
2250                              const ClutterActorBox  *box,
2251                              ClutterAllocationFlags  flags)
2252 {
2253   ClutterActorPrivate *priv = self->priv;
2254   gboolean changed;
2255
2256   g_object_freeze_notify (G_OBJECT (self));
2257
2258   changed = clutter_actor_set_allocation_internal (self, box, flags);
2259
2260   /* we allocate our children before we notify changes in our geometry,
2261    * so that people connecting to properties will be able to get valid
2262    * data out of the sub-tree of the scene graph that has this actor at
2263    * the root.
2264    */
2265   clutter_actor_maybe_layout_children (self, box, flags);
2266
2267   if (changed)
2268     {
2269       ClutterActorBox signal_box = priv->allocation;
2270       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2271
2272       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2273                      &signal_box,
2274                      signal_flags);
2275     }
2276
2277   g_object_thaw_notify (G_OBJECT (self));
2278 }
2279
2280 static void
2281 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2282                                     ClutterActor *origin)
2283 {
2284   /* no point in queuing a redraw on a destroyed actor */
2285   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2286     return;
2287
2288   /* NB: We can't bail out early here if the actor is hidden in case
2289    * the actor bas been cloned. In this case the clone will need to
2290    * receive the signal so it can queue its own redraw.
2291    */
2292
2293   /* calls klass->queue_redraw in default handler */
2294   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2295 }
2296
2297 static void
2298 clutter_actor_real_queue_redraw (ClutterActor *self,
2299                                  ClutterActor *origin)
2300 {
2301   ClutterActor *parent;
2302
2303   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2304                 _clutter_actor_get_debug_name (self),
2305                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2306                                : "same actor");
2307
2308   /* no point in queuing a redraw on a destroyed actor */
2309   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2310     return;
2311
2312   /* If the queue redraw is coming from a child then the actor has
2313      become dirty and any queued effect is no longer valid */
2314   if (self != origin)
2315     {
2316       self->priv->is_dirty = TRUE;
2317       self->priv->effect_to_redraw = NULL;
2318     }
2319
2320   /* If the actor isn't visible, we still had to emit the signal
2321    * to allow for a ClutterClone, but the appearance of the parent
2322    * won't change so we don't have to propagate up the hierarchy.
2323    */
2324   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2325     return;
2326
2327   /* Although we could determine here that a full stage redraw
2328    * has already been queued and immediately bail out, we actually
2329    * guarantee that we will propagate a queue-redraw signal to our
2330    * parent at least once so that it's possible to implement a
2331    * container that tracks which of its children have queued a
2332    * redraw.
2333    */
2334   if (self->priv->propagated_one_redraw)
2335     {
2336       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2337       if (stage != NULL &&
2338           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2339         return;
2340     }
2341
2342   self->priv->propagated_one_redraw = TRUE;
2343
2344   /* notify parents, if they are all visible eventually we'll
2345    * queue redraw on the stage, which queues the redraw idle.
2346    */
2347   parent = clutter_actor_get_parent (self);
2348   if (parent != NULL)
2349     {
2350       /* this will go up recursively */
2351       _clutter_actor_signal_queue_redraw (parent, origin);
2352     }
2353 }
2354
2355 static void
2356 clutter_actor_real_queue_relayout (ClutterActor *self)
2357 {
2358   ClutterActorPrivate *priv = self->priv;
2359
2360   /* no point in queueing a redraw on a destroyed actor */
2361   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2362     return;
2363
2364   priv->needs_width_request  = TRUE;
2365   priv->needs_height_request = TRUE;
2366   priv->needs_allocation     = TRUE;
2367
2368   /* reset the cached size requests */
2369   memset (priv->width_requests, 0,
2370           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371   memset (priv->height_requests, 0,
2372           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2373
2374   /* We need to go all the way up the hierarchy */
2375   if (priv->parent != NULL)
2376     _clutter_actor_queue_only_relayout (priv->parent);
2377 }
2378
2379 /**
2380  * clutter_actor_apply_relative_transform_to_point:
2381  * @self: A #ClutterActor
2382  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2383  *   default #ClutterStage
2384  * @point: A point as #ClutterVertex
2385  * @vertex: (out caller-allocates): The translated #ClutterVertex
2386  *
2387  * Transforms @point in coordinates relative to the actor into
2388  * ancestor-relative coordinates using the relevant transform
2389  * stack (i.e. scale, rotation, etc).
2390  *
2391  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2392  * this case, the coordinates returned will be the coordinates on
2393  * the stage before the projection is applied. This is different from
2394  * the behaviour of clutter_actor_apply_transform_to_point().
2395  *
2396  * Since: 0.6
2397  */
2398 void
2399 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2400                                                  ClutterActor        *ancestor,
2401                                                  const ClutterVertex *point,
2402                                                  ClutterVertex       *vertex)
2403 {
2404   gfloat w;
2405   CoglMatrix matrix;
2406
2407   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2408   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2409   g_return_if_fail (point != NULL);
2410   g_return_if_fail (vertex != NULL);
2411
2412   *vertex = *point;
2413   w = 1.0;
2414
2415   if (ancestor == NULL)
2416     ancestor = _clutter_actor_get_stage_internal (self);
2417
2418   if (ancestor == NULL)
2419     {
2420       *vertex = *point;
2421       return;
2422     }
2423
2424   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2425   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2426 }
2427
2428 static gboolean
2429 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2430                                          const ClutterVertex *vertices_in,
2431                                          ClutterVertex *vertices_out,
2432                                          int n_vertices)
2433 {
2434   ClutterActor *stage;
2435   CoglMatrix modelview;
2436   CoglMatrix projection;
2437   float viewport[4];
2438
2439   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2440
2441   stage = _clutter_actor_get_stage_internal (self);
2442
2443   /* We really can't do anything meaningful in this case so don't try
2444    * to do any transform */
2445   if (stage == NULL)
2446     return FALSE;
2447
2448   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2449    * that gets us to stage coordinates, we want to go all the way to eye
2450    * coordinates */
2451   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2452
2453   /* Fetch the projection and viewport */
2454   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2455   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2456                                &viewport[0],
2457                                &viewport[1],
2458                                &viewport[2],
2459                                &viewport[3]);
2460
2461   _clutter_util_fully_transform_vertices (&modelview,
2462                                           &projection,
2463                                           viewport,
2464                                           vertices_in,
2465                                           vertices_out,
2466                                           n_vertices);
2467
2468   return TRUE;
2469 }
2470
2471 /**
2472  * clutter_actor_apply_transform_to_point:
2473  * @self: A #ClutterActor
2474  * @point: A point as #ClutterVertex
2475  * @vertex: (out caller-allocates): The translated #ClutterVertex
2476  *
2477  * Transforms @point in coordinates relative to the actor
2478  * into screen-relative coordinates with the current actor
2479  * transformation (i.e. scale, rotation, etc)
2480  *
2481  * Since: 0.4
2482  **/
2483 void
2484 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2485                                         const ClutterVertex *point,
2486                                         ClutterVertex       *vertex)
2487 {
2488   g_return_if_fail (point != NULL);
2489   g_return_if_fail (vertex != NULL);
2490   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2491 }
2492
2493 /*
2494  * _clutter_actor_get_relative_transformation_matrix:
2495  * @self: The actor whose coordinate space you want to transform from.
2496  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2497  *            or %NULL if you want to transform all the way to eye coordinates.
2498  * @matrix: A #CoglMatrix to store the transformation
2499  *
2500  * This gets a transformation @matrix that will transform coordinates from the
2501  * coordinate space of @self into the coordinate space of @ancestor.
2502  *
2503  * For example if you need a matrix that can transform the local actor
2504  * coordinates of @self into stage coordinates you would pass the actor's stage
2505  * pointer as the @ancestor.
2506  *
2507  * If you pass %NULL then the transformation will take you all the way through
2508  * to eye coordinates. This can be useful if you want to extract the entire
2509  * modelview transform that Clutter applies before applying the projection
2510  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2511  * using cogl_set_modelview_matrix() for example then you would want a matrix
2512  * that transforms into eye coordinates.
2513  *
2514  * <note><para>This function explicitly initializes the given @matrix. If you just
2515  * want clutter to multiply a relative transformation with an existing matrix
2516  * you can use clutter_actor_apply_relative_transformation_matrix()
2517  * instead.</para></note>
2518  *
2519  */
2520 /* XXX: We should consider caching the stage relative modelview along with
2521  * the actor itself */
2522 static void
2523 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2524                                                    ClutterActor *ancestor,
2525                                                    CoglMatrix *matrix)
2526 {
2527   cogl_matrix_init_identity (matrix);
2528
2529   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2530 }
2531
2532 /* Project the given @box into stage window coordinates, writing the
2533  * transformed vertices to @verts[]. */
2534 static gboolean
2535 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2536                                           const ClutterActorBox *box,
2537                                           ClutterVertex          verts[])
2538 {
2539   ClutterVertex box_vertices[4];
2540
2541   box_vertices[0].x = box->x1;
2542   box_vertices[0].y = box->y1;
2543   box_vertices[0].z = 0;
2544   box_vertices[1].x = box->x2;
2545   box_vertices[1].y = box->y1;
2546   box_vertices[1].z = 0;
2547   box_vertices[2].x = box->x1;
2548   box_vertices[2].y = box->y2;
2549   box_vertices[2].z = 0;
2550   box_vertices[3].x = box->x2;
2551   box_vertices[3].y = box->y2;
2552   box_vertices[3].z = 0;
2553
2554   return
2555     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2556 }
2557
2558 /**
2559  * clutter_actor_get_allocation_vertices:
2560  * @self: A #ClutterActor
2561  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2562  *   against, or %NULL to use the #ClutterStage
2563  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2564  *   location for an array of 4 #ClutterVertex in which to store the result
2565  *
2566  * Calculates the transformed coordinates of the four corners of the
2567  * actor in the plane of @ancestor. The returned vertices relate to
2568  * the #ClutterActorBox coordinates as follows:
2569  * <itemizedlist>
2570  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2571  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2572  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2573  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2574  * </itemizedlist>
2575  *
2576  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577  * this case, the coordinates returned will be the coordinates on
2578  * the stage before the projection is applied. This is different from
2579  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2580  *
2581  * Since: 0.6
2582  */
2583 void
2584 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2585                                        ClutterActor  *ancestor,
2586                                        ClutterVertex  verts[])
2587 {
2588   ClutterActorPrivate *priv;
2589   ClutterActorBox box;
2590   ClutterVertex vertices[4];
2591   CoglMatrix modelview;
2592
2593   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2594   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2595
2596   if (ancestor == NULL)
2597     ancestor = _clutter_actor_get_stage_internal (self);
2598
2599   /* Fallback to a NOP transform if the actor isn't parented under a
2600    * stage. */
2601   if (ancestor == NULL)
2602     ancestor = self;
2603
2604   priv = self->priv;
2605
2606   /* if the actor needs to be allocated we force a relayout, so that
2607    * we will have valid values to use in the transformations */
2608   if (priv->needs_allocation)
2609     {
2610       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2611       if (stage)
2612         _clutter_stage_maybe_relayout (stage);
2613       else
2614         {
2615           box.x1 = box.y1 = 0;
2616           /* The result isn't really meaningful in this case but at
2617            * least try to do something *vaguely* reasonable... */
2618           clutter_actor_get_size (self, &box.x2, &box.y2);
2619         }
2620     }
2621
2622   clutter_actor_get_allocation_box (self, &box);
2623
2624   vertices[0].x = box.x1;
2625   vertices[0].y = box.y1;
2626   vertices[0].z = 0;
2627   vertices[1].x = box.x2;
2628   vertices[1].y = box.y1;
2629   vertices[1].z = 0;
2630   vertices[2].x = box.x1;
2631   vertices[2].y = box.y2;
2632   vertices[2].z = 0;
2633   vertices[3].x = box.x2;
2634   vertices[3].y = box.y2;
2635   vertices[3].z = 0;
2636
2637   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2638                                                      &modelview);
2639
2640   cogl_matrix_transform_points (&modelview,
2641                                 3,
2642                                 sizeof (ClutterVertex),
2643                                 vertices,
2644                                 sizeof (ClutterVertex),
2645                                 vertices,
2646                                 4);
2647 }
2648
2649 /**
2650  * clutter_actor_get_abs_allocation_vertices:
2651  * @self: A #ClutterActor
2652  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2653  *   of 4 #ClutterVertex where to store the result.
2654  *
2655  * Calculates the transformed screen coordinates of the four corners of
2656  * the actor; the returned vertices relate to the #ClutterActorBox
2657  * coordinates  as follows:
2658  * <itemizedlist>
2659  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2660  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2661  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2662  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2663  * </itemizedlist>
2664  *
2665  * Since: 0.4
2666  */
2667 void
2668 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2669                                            ClutterVertex  verts[])
2670 {
2671   ClutterActorPrivate *priv;
2672   ClutterActorBox actor_space_allocation;
2673
2674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2675
2676   priv = self->priv;
2677
2678   /* if the actor needs to be allocated we force a relayout, so that
2679    * the actor allocation box will be valid for
2680    * _clutter_actor_transform_and_project_box()
2681    */
2682   if (priv->needs_allocation)
2683     {
2684       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2685       /* There's nothing meaningful we can do now */
2686       if (!stage)
2687         return;
2688
2689       _clutter_stage_maybe_relayout (stage);
2690     }
2691
2692   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2693    * own coordinate space... */
2694   actor_space_allocation.x1 = 0;
2695   actor_space_allocation.y1 = 0;
2696   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2697   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2698   _clutter_actor_transform_and_project_box (self,
2699                                             &actor_space_allocation,
2700                                             verts);
2701 }
2702
2703 static void
2704 clutter_actor_real_apply_transform (ClutterActor *self,
2705                                     CoglMatrix   *matrix)
2706 {
2707   ClutterActorPrivate *priv = self->priv;
2708
2709   if (!priv->transform_valid)
2710     {
2711       CoglMatrix *transform = &priv->transform;
2712       const ClutterTransformInfo *info;
2713
2714       info = _clutter_actor_get_transform_info_or_defaults (self);
2715
2716       cogl_matrix_init_identity (transform);
2717
2718       cogl_matrix_translate (transform,
2719                              priv->allocation.x1,
2720                              priv->allocation.y1,
2721                              0.0);
2722
2723       if (info->depth)
2724         cogl_matrix_translate (transform, 0, 0, info->depth);
2725
2726       /*
2727        * because the rotation involves translations, we must scale
2728        * before applying the rotations (if we apply the scale after
2729        * the rotations, the translations included in the rotation are
2730        * not scaled and so the entire object will move on the screen
2731        * as a result of rotating it).
2732        */
2733       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2734         {
2735           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2736                                         &info->scale_center,
2737                                         cogl_matrix_scale (transform,
2738                                                            info->scale_x,
2739                                                            info->scale_y,
2740                                                            1.0));
2741         }
2742
2743       if (info->rz_angle)
2744         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2745                                       &info->rz_center,
2746                                       cogl_matrix_rotate (transform,
2747                                                           info->rz_angle,
2748                                                           0, 0, 1.0));
2749
2750       if (info->ry_angle)
2751         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2752                                       &info->ry_center,
2753                                       cogl_matrix_rotate (transform,
2754                                                           info->ry_angle,
2755                                                           0, 1.0, 0));
2756
2757       if (info->rx_angle)
2758         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2759                                       &info->rx_center,
2760                                       cogl_matrix_rotate (transform,
2761                                                           info->rx_angle,
2762                                                           1.0, 0, 0));
2763
2764       if (!clutter_anchor_coord_is_zero (&info->anchor))
2765         {
2766           gfloat x, y, z;
2767
2768           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2769           cogl_matrix_translate (transform, -x, -y, -z);
2770         }
2771
2772       priv->transform_valid = TRUE;
2773     }
2774
2775   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2776 }
2777
2778 /* Applies the transforms associated with this actor to the given
2779  * matrix. */
2780 void
2781 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2782                                           CoglMatrix *matrix)
2783 {
2784   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2785 }
2786
2787 /*
2788  * clutter_actor_apply_relative_transformation_matrix:
2789  * @self: The actor whose coordinate space you want to transform from.
2790  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2791  *            or %NULL if you want to transform all the way to eye coordinates.
2792  * @matrix: A #CoglMatrix to apply the transformation too.
2793  *
2794  * This multiplies a transform with @matrix that will transform coordinates
2795  * from the coordinate space of @self into the coordinate space of @ancestor.
2796  *
2797  * For example if you need a matrix that can transform the local actor
2798  * coordinates of @self into stage coordinates you would pass the actor's stage
2799  * pointer as the @ancestor.
2800  *
2801  * If you pass %NULL then the transformation will take you all the way through
2802  * to eye coordinates. This can be useful if you want to extract the entire
2803  * modelview transform that Clutter applies before applying the projection
2804  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2805  * using cogl_set_modelview_matrix() for example then you would want a matrix
2806  * that transforms into eye coordinates.
2807  *
2808  * <note>This function doesn't initialize the given @matrix, it simply
2809  * multiplies the requested transformation matrix with the existing contents of
2810  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2811  * before calling this function, or you can use
2812  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2813  */
2814 void
2815 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2816                                                      ClutterActor *ancestor,
2817                                                      CoglMatrix *matrix)
2818 {
2819   ClutterActor *parent;
2820
2821   /* Note we terminate before ever calling stage->apply_transform()
2822    * since that would conceptually be relative to the underlying
2823    * window OpenGL coordinates so we'd need a special @ancestor
2824    * value to represent the fake parent of the stage. */
2825   if (self == ancestor)
2826     return;
2827
2828   parent = clutter_actor_get_parent (self);
2829
2830   if (parent != NULL)
2831     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2832                                                          matrix);
2833
2834   _clutter_actor_apply_modelview_transform (self, matrix);
2835 }
2836
2837 static void
2838 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2839                                        ClutterPaintVolume *pv,
2840                                        const char *label,
2841                                        const CoglColor *color)
2842 {
2843   static CoglPipeline *outline = NULL;
2844   CoglPrimitive *prim;
2845   ClutterVertex line_ends[12 * 2];
2846   int n_vertices;
2847   CoglContext *ctx =
2848     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2849   /* XXX: at some point we'll query this from the stage but we can't
2850    * do that until the osx backend uses Cogl natively. */
2851   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2852
2853   if (outline == NULL)
2854     outline = cogl_pipeline_new (ctx);
2855
2856   _clutter_paint_volume_complete (pv);
2857
2858   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2859
2860   /* Front face */
2861   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2862   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2863   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2864   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2865
2866   if (!pv->is_2d)
2867     {
2868       /* Back face */
2869       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2870       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2871       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2872       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2873
2874       /* Lines connecting front face to back face */
2875       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2876       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2877       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2878       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2879     }
2880
2881   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2882                                 n_vertices,
2883                                 (CoglVertexP3 *)line_ends);
2884
2885   cogl_pipeline_set_color (outline, color);
2886   cogl_framebuffer_draw_primitive (fb, outline, prim);
2887   cogl_object_unref (prim);
2888
2889   if (label)
2890     {
2891       PangoLayout *layout;
2892       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2893       pango_layout_set_text (layout, label, -1);
2894       cogl_pango_render_layout (layout,
2895                                 pv->vertices[0].x,
2896                                 pv->vertices[0].y,
2897                                 color,
2898                                 0);
2899       g_object_unref (layout);
2900     }
2901 }
2902
2903 static void
2904 _clutter_actor_draw_paint_volume (ClutterActor *self)
2905 {
2906   ClutterPaintVolume *pv;
2907   CoglColor color;
2908
2909   pv = _clutter_actor_get_paint_volume_mutable (self);
2910   if (!pv)
2911     {
2912       gfloat width, height;
2913       ClutterPaintVolume fake_pv;
2914
2915       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2916       _clutter_paint_volume_init_static (&fake_pv, stage);
2917
2918       clutter_actor_get_size (self, &width, &height);
2919       clutter_paint_volume_set_width (&fake_pv, width);
2920       clutter_paint_volume_set_height (&fake_pv, height);
2921
2922       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2923       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2924                                              _clutter_actor_get_debug_name (self),
2925                                              &color);
2926
2927       clutter_paint_volume_free (&fake_pv);
2928     }
2929   else
2930     {
2931       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2932       _clutter_actor_draw_paint_volume_full (self, pv,
2933                                              _clutter_actor_get_debug_name (self),
2934                                              &color);
2935     }
2936 }
2937
2938 static void
2939 _clutter_actor_paint_cull_result (ClutterActor *self,
2940                                   gboolean success,
2941                                   ClutterCullResult result)
2942 {
2943   ClutterPaintVolume *pv;
2944   CoglColor color;
2945
2946   if (success)
2947     {
2948       if (result == CLUTTER_CULL_RESULT_IN)
2949         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2950       else if (result == CLUTTER_CULL_RESULT_OUT)
2951         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2952       else
2953         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2954     }
2955   else
2956     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2957
2958   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2959     _clutter_actor_draw_paint_volume_full (self, pv,
2960                                            _clutter_actor_get_debug_name (self),
2961                                            &color);
2962   else
2963     {
2964       PangoLayout *layout;
2965       char *label =
2966         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2967       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2968       cogl_set_source_color (&color);
2969
2970       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2971       pango_layout_set_text (layout, label, -1);
2972       cogl_pango_render_layout (layout,
2973                                 0,
2974                                 0,
2975                                 &color,
2976                                 0);
2977       g_free (label);
2978       g_object_unref (layout);
2979     }
2980 }
2981
2982 static int clone_paint_level = 0;
2983
2984 void
2985 _clutter_actor_push_clone_paint (void)
2986 {
2987   clone_paint_level++;
2988 }
2989
2990 void
2991 _clutter_actor_pop_clone_paint (void)
2992 {
2993   clone_paint_level--;
2994 }
2995
2996 static gboolean
2997 in_clone_paint (void)
2998 {
2999   return clone_paint_level > 0;
3000 }
3001
3002 /* Returns TRUE if the actor can be ignored */
3003 /* FIXME: we should return a ClutterCullResult, and
3004  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3005  * means there's no point in trying to cull descendants of the current
3006  * node. */
3007 static gboolean
3008 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3009 {
3010   ClutterActorPrivate *priv = self->priv;
3011   ClutterActor *stage;
3012   const ClutterPlane *stage_clip;
3013
3014   if (!priv->last_paint_volume_valid)
3015     {
3016       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3017                     "->last_paint_volume_valid == FALSE",
3018                     _clutter_actor_get_debug_name (self));
3019       return FALSE;
3020     }
3021
3022   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3023     return FALSE;
3024
3025   stage = _clutter_actor_get_stage_internal (self);
3026   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3027   if (G_UNLIKELY (!stage_clip))
3028     {
3029       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3030                     "No stage clip set",
3031                     _clutter_actor_get_debug_name (self));
3032       return FALSE;
3033     }
3034
3035   if (cogl_get_draw_framebuffer () !=
3036       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3037     {
3038       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3039                     "Current framebuffer doesn't correspond to stage",
3040                     _clutter_actor_get_debug_name (self));
3041       return FALSE;
3042     }
3043
3044   *result_out =
3045     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3046   return TRUE;
3047 }
3048
3049 static void
3050 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3051 {
3052   ClutterActorPrivate *priv = self->priv;
3053   const ClutterPaintVolume *pv;
3054
3055   if (priv->last_paint_volume_valid)
3056     {
3057       clutter_paint_volume_free (&priv->last_paint_volume);
3058       priv->last_paint_volume_valid = FALSE;
3059     }
3060
3061   pv = clutter_actor_get_paint_volume (self);
3062   if (!pv)
3063     {
3064       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3065                     "Actor failed to report a paint volume",
3066                     _clutter_actor_get_debug_name (self));
3067       return;
3068     }
3069
3070   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3071
3072   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3073                                             NULL); /* eye coordinates */
3074
3075   priv->last_paint_volume_valid = TRUE;
3076 }
3077
3078 static inline gboolean
3079 actor_has_shader_data (ClutterActor *self)
3080 {
3081   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3082 }
3083
3084 guint32
3085 _clutter_actor_get_pick_id (ClutterActor *self)
3086 {
3087   if (self->priv->pick_id < 0)
3088     return 0;
3089
3090   return self->priv->pick_id;
3091 }
3092
3093 /* This is the same as clutter_actor_add_effect except that it doesn't
3094    queue a redraw and it doesn't notify on the effect property */
3095 static void
3096 _clutter_actor_add_effect_internal (ClutterActor  *self,
3097                                     ClutterEffect *effect)
3098 {
3099   ClutterActorPrivate *priv = self->priv;
3100
3101   if (priv->effects == NULL)
3102     {
3103       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3104       priv->effects->actor = self;
3105     }
3106
3107   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3108 }
3109
3110 /* This is the same as clutter_actor_remove_effect except that it doesn't
3111    queue a redraw and it doesn't notify on the effect property */
3112 static void
3113 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3114                                        ClutterEffect *effect)
3115 {
3116   ClutterActorPrivate *priv = self->priv;
3117
3118   if (priv->effects == NULL)
3119     return;
3120
3121   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3122 }
3123
3124 static gboolean
3125 needs_flatten_effect (ClutterActor *self)
3126 {
3127   ClutterActorPrivate *priv = self->priv;
3128
3129   if (G_UNLIKELY (clutter_paint_debug_flags &
3130                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3131     return FALSE;
3132
3133   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3134     return TRUE;
3135   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3136     {
3137       if (clutter_actor_get_paint_opacity (self) < 255 &&
3138           clutter_actor_has_overlaps (self))
3139         return TRUE;
3140     }
3141
3142   return FALSE;
3143 }
3144
3145 static void
3146 add_or_remove_flatten_effect (ClutterActor *self)
3147 {
3148   ClutterActorPrivate *priv = self->priv;
3149
3150   /* Add or remove the flatten effect depending on the
3151      offscreen-redirect property. */
3152   if (needs_flatten_effect (self))
3153     {
3154       if (priv->flatten_effect == NULL)
3155         {
3156           ClutterActorMeta *actor_meta;
3157           gint priority;
3158
3159           priv->flatten_effect = _clutter_flatten_effect_new ();
3160           /* Keep a reference to the effect so that we can queue
3161              redraws from it */
3162           g_object_ref_sink (priv->flatten_effect);
3163
3164           /* Set the priority of the effect to high so that it will
3165              always be applied to the actor first. It uses an internal
3166              priority so that it won't be visible to applications */
3167           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3168           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3169           _clutter_actor_meta_set_priority (actor_meta, priority);
3170
3171           /* This will add the effect without queueing a redraw */
3172           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3173         }
3174     }
3175   else
3176     {
3177       if (priv->flatten_effect != NULL)
3178         {
3179           /* Destroy the effect so that it will lose its fbo cache of
3180              the actor */
3181           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3182           g_object_unref (priv->flatten_effect);
3183           priv->flatten_effect = NULL;
3184         }
3185     }
3186 }
3187
3188 static void
3189 clutter_actor_real_paint (ClutterActor *actor)
3190 {
3191   ClutterActorPrivate *priv = actor->priv;
3192   ClutterActor *iter;
3193
3194   for (iter = priv->first_child;
3195        iter != NULL;
3196        iter = iter->priv->next_sibling)
3197     {
3198       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199                     _clutter_actor_get_debug_name (iter),
3200                     _clutter_actor_get_debug_name (actor),
3201                     iter->priv->allocation.x1,
3202                     iter->priv->allocation.y1,
3203                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3205
3206       clutter_actor_paint (iter);
3207     }
3208 }
3209
3210 static gboolean
3211 clutter_actor_paint_node (ClutterActor     *actor,
3212                           ClutterPaintNode *root)
3213 {
3214   ClutterActorPrivate *priv = actor->priv;
3215
3216   if (root == NULL)
3217     return FALSE;
3218
3219   if (priv->bg_color_set &&
3220       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3221     {
3222       ClutterPaintNode *node;
3223       ClutterColor bg_color;
3224       ClutterActorBox box;
3225
3226       box.x1 = 0.f;
3227       box.y1 = 0.f;
3228       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3230
3231       bg_color = priv->bg_color;
3232       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233                      * priv->bg_color.alpha
3234                      / 255;
3235
3236       node = clutter_color_node_new (&bg_color);
3237       clutter_paint_node_set_name (node, "backgroundColor");
3238       clutter_paint_node_add_rectangle (node, &box);
3239       clutter_paint_node_add_child (root, node);
3240       clutter_paint_node_unref (node);
3241     }
3242
3243   if (priv->content != NULL)
3244     _clutter_content_paint_content (priv->content, actor, root);
3245
3246   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3248
3249   if (clutter_paint_node_get_n_children (root) == 0)
3250     return FALSE;
3251
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253   if (CLUTTER_HAS_DEBUG (PAINT))
3254     {
3255       /* dump the tree only if we have one */
3256       _clutter_paint_node_dump_tree (root);
3257     }
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3259
3260   _clutter_paint_node_paint (root);
3261
3262 #if 0
3263   /* XXX: Uncomment this when we disable emitting the paint signal */
3264   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3265 #endif
3266
3267   return TRUE;
3268 }
3269
3270 /**
3271  * clutter_actor_paint:
3272  * @self: A #ClutterActor
3273  *
3274  * Renders the actor to display.
3275  *
3276  * This function should not be called directly by applications.
3277  * Call clutter_actor_queue_redraw() to queue paints, instead.
3278  *
3279  * This function is context-aware, and will either cause a
3280  * regular paint or a pick paint.
3281  *
3282  * This function will emit the #ClutterActor::paint signal or
3283  * the #ClutterActor::pick signal, depending on the context.
3284  *
3285  * This function does not paint the actor if the actor is set to 0,
3286  * unless it is performing a pick paint.
3287  */
3288 void
3289 clutter_actor_paint (ClutterActor *self)
3290 {
3291   ClutterActorPrivate *priv;
3292   ClutterPickMode pick_mode;
3293   gboolean clip_set = FALSE;
3294   gboolean shader_applied = FALSE;
3295
3296   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297                           "Actor real-paint counter",
3298                           "Increments each time any actor is painted",
3299                           0 /* no application private data */);
3300   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301                           "Actor pick-paint counter",
3302                           "Increments each time any actor is painted "
3303                           "for picking",
3304                           0 /* no application private data */);
3305
3306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3307
3308   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3309     return;
3310
3311   priv = self->priv;
3312
3313   pick_mode = _clutter_context_get_pick_mode ();
3314
3315   if (pick_mode == CLUTTER_PICK_NONE)
3316     priv->propagated_one_redraw = FALSE;
3317
3318   /* It's an important optimization that we consider painting of
3319    * actors with 0 opacity to be a NOP... */
3320   if (pick_mode == CLUTTER_PICK_NONE &&
3321       /* ignore top-levels, since they might be transparent */
3322       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323       /* Use the override opacity if its been set */
3324       ((priv->opacity_override >= 0) ?
3325        priv->opacity_override : priv->opacity) == 0)
3326     return;
3327
3328   /* if we aren't paintable (not in a toplevel with all
3329    * parents paintable) then do nothing.
3330    */
3331   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3332     return;
3333
3334   /* mark that we are in the paint process */
3335   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3336
3337   cogl_push_matrix();
3338
3339   if (priv->enable_model_view_transform)
3340     {
3341       CoglMatrix matrix;
3342
3343       /* XXX: It could be better to cache the modelview with the actor
3344        * instead of progressively building up the transformations on
3345        * the matrix stack every time we paint. */
3346       cogl_get_modelview_matrix (&matrix);
3347       _clutter_actor_apply_modelview_transform (self, &matrix);
3348
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350       /* Catch when out-of-band transforms have been made by actors not as part
3351        * of an apply_transform vfunc... */
3352       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3353         {
3354           CoglMatrix expected_matrix;
3355
3356           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3357                                                              &expected_matrix);
3358
3359           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3360             {
3361               GString *buf = g_string_sized_new (1024);
3362               ClutterActor *parent;
3363
3364               parent = self;
3365               while (parent != NULL)
3366                 {
3367                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3368
3369                   if (parent->priv->parent != NULL)
3370                     g_string_append (buf, "->");
3371
3372                   parent = parent->priv->parent;
3373                 }
3374
3375               g_warning ("Unexpected transform found when painting actor "
3376                          "\"%s\". This will be caused by one of the actor's "
3377                          "ancestors (%s) using the Cogl API directly to transform "
3378                          "children instead of using ::apply_transform().",
3379                          _clutter_actor_get_debug_name (self),
3380                          buf->str);
3381
3382               g_string_free (buf, TRUE);
3383             }
3384         }
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3386
3387       cogl_set_modelview_matrix (&matrix);
3388     }
3389
3390   if (priv->has_clip)
3391     {
3392       cogl_clip_push_rectangle (priv->clip.x,
3393                                 priv->clip.y,
3394                                 priv->clip.x + priv->clip.width,
3395                                 priv->clip.y + priv->clip.height);
3396       clip_set = TRUE;
3397     }
3398   else if (priv->clip_to_allocation)
3399     {
3400       gfloat width, height;
3401
3402       width  = priv->allocation.x2 - priv->allocation.x1;
3403       height = priv->allocation.y2 - priv->allocation.y1;
3404
3405       cogl_clip_push_rectangle (0, 0, width, height);
3406       clip_set = TRUE;
3407     }
3408
3409   if (pick_mode == CLUTTER_PICK_NONE)
3410     {
3411       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3412
3413       /* We check whether we need to add the flatten effect before
3414          each paint so that we can avoid having a mechanism for
3415          applications to notify when the value of the
3416          has_overlaps virtual changes. */
3417       add_or_remove_flatten_effect (self);
3418     }
3419   else
3420     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3421
3422   /* We save the current paint volume so that the next time the
3423    * actor queues a redraw we can constrain the redraw to just
3424    * cover the union of the new bounding box and the old.
3425    *
3426    * We also fetch the current paint volume to perform culling so
3427    * we can avoid painting actors outside the current clip region.
3428    *
3429    * If we are painting inside a clone, we should neither update
3430    * the paint volume or use it to cull painting, since the paint
3431    * box represents the location of the source actor on the
3432    * screen.
3433    *
3434    * XXX: We are starting to do a lot of vertex transforms on
3435    * the CPU in a typical paint, so at some point we should
3436    * audit these and consider caching some things.
3437    *
3438    * NB: We don't perform culling while picking at this point because
3439    * clutter-stage.c doesn't setup the clipping planes appropriately.
3440    *
3441    * NB: We don't want to update the last-paint-volume during picking
3442    * because the last-paint-volume is used to determine the old screen
3443    * space location of an actor that has moved so we can know the
3444    * minimal region to redraw to clear an old view of the actor. If we
3445    * update this during picking then by the time we come around to
3446    * paint then the last-paint-volume would likely represent the new
3447    * actor position not the old.
3448    */
3449   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3450     {
3451       gboolean success;
3452       /* annoyingly gcc warns if uninitialized even though
3453        * the initialization is redundant :-( */
3454       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3455
3456       if (G_LIKELY ((clutter_paint_debug_flags &
3457                      (CLUTTER_DEBUG_DISABLE_CULLING |
3458                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459                     (CLUTTER_DEBUG_DISABLE_CULLING |
3460                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461         _clutter_actor_update_last_paint_volume (self);
3462
3463       success = cull_actor (self, &result);
3464
3465       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466         _clutter_actor_paint_cull_result (self, success, result);
3467       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3468         goto done;
3469     }
3470
3471   if (priv->effects == NULL)
3472     {
3473       if (pick_mode == CLUTTER_PICK_NONE &&
3474           actor_has_shader_data (self))
3475         {
3476           _clutter_actor_shader_pre_paint (self, FALSE);
3477           shader_applied = TRUE;
3478         }
3479
3480       priv->next_effect_to_paint = NULL;
3481     }
3482   else
3483     priv->next_effect_to_paint =
3484       _clutter_meta_group_peek_metas (priv->effects);
3485
3486   clutter_actor_continue_paint (self);
3487
3488   if (shader_applied)
3489     _clutter_actor_shader_post_paint (self);
3490
3491   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492                   pick_mode == CLUTTER_PICK_NONE))
3493     _clutter_actor_draw_paint_volume (self);
3494
3495 done:
3496   /* If we make it here then the actor has run through a complete
3497      paint run including all the effects so it's no longer dirty */
3498   if (pick_mode == CLUTTER_PICK_NONE)
3499     priv->is_dirty = FALSE;
3500
3501   if (clip_set)
3502     cogl_clip_pop();
3503
3504   cogl_pop_matrix();
3505
3506   /* paint sequence complete */
3507   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3508 }
3509
3510 /**
3511  * clutter_actor_continue_paint:
3512  * @self: A #ClutterActor
3513  *
3514  * Run the next stage of the paint sequence. This function should only
3515  * be called within the implementation of the ‘run’ virtual of a
3516  * #ClutterEffect. It will cause the run method of the next effect to
3517  * be applied, or it will paint the actual actor if the current effect
3518  * is the last effect in the chain.
3519  *
3520  * Since: 1.8
3521  */
3522 void
3523 clutter_actor_continue_paint (ClutterActor *self)
3524 {
3525   ClutterActorPrivate *priv;
3526
3527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528   /* This should only be called from with in the ‘run’ implementation
3529      of a ClutterEffect */
3530   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3531
3532   priv = self->priv;
3533
3534   /* Skip any effects that are disabled */
3535   while (priv->next_effect_to_paint &&
3536          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3538
3539   /* If this has come from the last effect then we'll just paint the
3540      actual actor */
3541   if (priv->next_effect_to_paint == NULL)
3542     {
3543       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3544         {
3545           ClutterPaintNode *dummy;
3546
3547           /* XXX - this will go away in 2.0, when we can get rid of this
3548            * stuff and switch to a pure retained render tree of PaintNodes
3549            * for the entire frame, starting from the Stage; the paint()
3550            * virtual function can then be called directly.
3551            */
3552           dummy = _clutter_dummy_node_new (self);
3553           clutter_paint_node_set_name (dummy, "Root");
3554
3555           /* XXX - for 1.12, we use the return value of paint_node() to
3556            * decide whether we should emit the ::paint signal.
3557            */
3558           clutter_actor_paint_node (self, dummy);
3559           clutter_paint_node_unref (dummy);
3560
3561           g_signal_emit (self, actor_signals[PAINT], 0);
3562         }
3563       else
3564         {
3565           ClutterColor col = { 0, };
3566
3567           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3568
3569           /* Actor will then paint silhouette of itself in supplied
3570            * color.  See clutter_stage_get_actor_at_pos() for where
3571            * picking is enabled.
3572            */
3573           g_signal_emit (self, actor_signals[PICK], 0, &col);
3574         }
3575     }
3576   else
3577     {
3578       ClutterEffect *old_current_effect;
3579       ClutterEffectPaintFlags run_flags = 0;
3580
3581       /* Cache the current effect so that we can put it back before
3582          returning */
3583       old_current_effect = priv->current_effect;
3584
3585       priv->current_effect = priv->next_effect_to_paint->data;
3586       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3587
3588       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3589         {
3590           if (priv->is_dirty)
3591             {
3592               /* If there's an effect queued with this redraw then all
3593                  effects up to that one will be considered dirty. It
3594                  is expected the queued effect will paint the cached
3595                  image and not call clutter_actor_continue_paint again
3596                  (although it should work ok if it does) */
3597               if (priv->effect_to_redraw == NULL ||
3598                   priv->current_effect != priv->effect_to_redraw)
3599                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3600             }
3601
3602           _clutter_effect_paint (priv->current_effect, run_flags);
3603         }
3604       else
3605         {
3606           /* We can't determine when an actor has been modified since
3607              its last pick so lets just assume it has always been
3608              modified */
3609           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3610
3611           _clutter_effect_pick (priv->current_effect, run_flags);
3612         }
3613
3614       priv->current_effect = old_current_effect;
3615     }
3616 }
3617
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3620                                int           depth,
3621                                gpointer      user_data)
3622 {
3623   ClutterActorPrivate *priv = self->priv;
3624
3625   if (priv->queue_redraw_entry != NULL)
3626     {
3627       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628       priv->queue_redraw_entry = NULL;
3629     }
3630
3631   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3632 }
3633
3634 static inline void
3635 remove_child (ClutterActor *self,
3636               ClutterActor *child)
3637 {
3638   ClutterActor *prev_sibling, *next_sibling;
3639
3640   prev_sibling = child->priv->prev_sibling;
3641   next_sibling = child->priv->next_sibling;
3642
3643   if (prev_sibling != NULL)
3644     prev_sibling->priv->next_sibling = next_sibling;
3645
3646   if (next_sibling != NULL)
3647     next_sibling->priv->prev_sibling = prev_sibling;
3648
3649   if (self->priv->first_child == child)
3650     self->priv->first_child = next_sibling;
3651
3652   if (self->priv->last_child == child)
3653     self->priv->last_child = prev_sibling;
3654
3655   child->priv->parent = NULL;
3656   child->priv->prev_sibling = NULL;
3657   child->priv->next_sibling = NULL;
3658 }
3659
3660 typedef enum {
3661   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3662   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3663   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3665   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3666   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3667
3668   /* default flags for public API */
3669   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3670                                     REMOVE_CHILD_EMIT_PARENT_SET |
3671                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672                                     REMOVE_CHILD_CHECK_STATE |
3673                                     REMOVE_CHILD_FLUSH_QUEUE |
3674                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3675
3676   /* flags for legacy/deprecated API */
3677   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3678                                     REMOVE_CHILD_FLUSH_QUEUE |
3679                                     REMOVE_CHILD_EMIT_PARENT_SET |
3680                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3682
3683 /*< private >
3684  * clutter_actor_remove_child_internal:
3685  * @self: a #ClutterActor
3686  * @child: the child of @self that has to be removed
3687  * @flags: control the removal operations
3688  *
3689  * Removes @child from the list of children of @self.
3690  */
3691 static void
3692 clutter_actor_remove_child_internal (ClutterActor                 *self,
3693                                      ClutterActor                 *child,
3694                                      ClutterActorRemoveChildFlags  flags)
3695 {
3696   ClutterActor *old_first, *old_last;
3697   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698   gboolean flush_queue;
3699   gboolean notify_first_last;
3700   gboolean was_mapped;
3701
3702   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3708
3709   g_object_freeze_notify (G_OBJECT (self));
3710
3711   if (destroy_meta)
3712     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3713
3714   if (check_state)
3715     {
3716       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3717
3718       /* we need to unrealize *before* we set parent_actor to NULL,
3719        * because in an unrealize method actors are dissociating from the
3720        * stage, which means they need to be able to
3721        * clutter_actor_get_stage().
3722        *
3723        * yhis should unmap and unrealize, unless we're reparenting.
3724        */
3725       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3726     }
3727   else
3728     was_mapped = FALSE;
3729
3730   if (flush_queue)
3731     {
3732       /* We take this opportunity to invalidate any queue redraw entry
3733        * associated with the actor and descendants since we won't be able to
3734        * determine the appropriate stage after this.
3735        *
3736        * we do this after we updated the mapped state because actors might
3737        * end up queueing redraws inside their mapped/unmapped virtual
3738        * functions, and if we invalidate the redraw entry we could end up
3739        * with an inconsistent state and weird memory corruption. see
3740        * bugs:
3741        *
3742        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3744        */
3745       _clutter_actor_traverse (child,
3746                                0,
3747                                invalidate_queue_redraw_entry,
3748                                NULL,
3749                                NULL);
3750     }
3751
3752   old_first = self->priv->first_child;
3753   old_last = self->priv->last_child;
3754
3755   remove_child (self, child);
3756
3757   self->priv->n_children -= 1;
3758
3759   self->priv->age += 1;
3760
3761   /* clutter_actor_reparent() will emit ::parent-set for us */
3762   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3764
3765   /* if the child was mapped then we need to relayout ourselves to account
3766    * for the removed child
3767    */
3768   if (was_mapped)
3769     clutter_actor_queue_relayout (self);
3770
3771   /* we need to emit the signal before dropping the reference */
3772   if (emit_actor_removed)
3773     g_signal_emit_by_name (self, "actor-removed", child);
3774
3775   if (notify_first_last)
3776     {
3777       if (old_first != self->priv->first_child)
3778         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3779
3780       if (old_last != self->priv->last_child)
3781         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3782     }
3783
3784   g_object_thaw_notify (G_OBJECT (self));
3785
3786   /* remove the reference we acquired in clutter_actor_add_child() */
3787   g_object_unref (child);
3788 }
3789
3790 static const ClutterTransformInfo default_transform_info = {
3791   0.0, { 0, },          /* rotation-x */
3792   0.0, { 0, },          /* rotation-y */
3793   0.0, { 0, },          /* rotation-z */
3794
3795   1.0, 1.0, { 0, },     /* scale */
3796
3797   { 0, },               /* anchor */
3798
3799   0.0,                  /* depth */
3800 };
3801
3802 /*< private >
3803  * _clutter_actor_get_transform_info_or_defaults:
3804  * @self: a #ClutterActor
3805  *
3806  * Retrieves the ClutterTransformInfo structure associated to an actor.
3807  *
3808  * If the actor does not have a ClutterTransformInfo structure associated
3809  * to it, then the default structure will be returned.
3810  *
3811  * This function should only be used for getters.
3812  *
3813  * Return value: a const pointer to the ClutterTransformInfo structure
3814  */
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3817 {
3818   ClutterTransformInfo *info;
3819
3820   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3821   if (info != NULL)
3822     return info;
3823
3824   return &default_transform_info;
3825 }
3826
3827 static void
3828 clutter_transform_info_free (gpointer data)
3829 {
3830   if (data != NULL)
3831     g_slice_free (ClutterTransformInfo, data);
3832 }
3833
3834 /*< private >
3835  * _clutter_actor_get_transform_info:
3836  * @self: a #ClutterActor
3837  *
3838  * Retrieves a pointer to the ClutterTransformInfo structure.
3839  *
3840  * If the actor does not have a ClutterTransformInfo associated to it, one
3841  * will be created and initialized to the default values.
3842  *
3843  * This function should be used for setters.
3844  *
3845  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3846  * instead.
3847  *
3848  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3849  *   structure
3850  */
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3853 {
3854   ClutterTransformInfo *info;
3855
3856   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3857   if (info == NULL)
3858     {
3859       info = g_slice_new (ClutterTransformInfo);
3860
3861       *info = default_transform_info;
3862
3863       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3864                                info,
3865                                clutter_transform_info_free);
3866     }
3867
3868   return info;
3869 }
3870
3871 /*< private >
3872  * clutter_actor_set_rotation_angle_internal:
3873  * @self: a #ClutterActor
3874  * @axis: the axis of the angle to change
3875  * @angle: the angle of rotation
3876  *
3877  * Sets the rotation angle on the given axis without affecting the
3878  * rotation center point.
3879  */
3880 static inline void
3881 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3882                                            ClutterRotateAxis  axis,
3883                                            gdouble            angle)
3884 {
3885   GObject *obj = G_OBJECT (self);
3886   ClutterTransformInfo *info;
3887
3888   info = _clutter_actor_get_transform_info (self);
3889
3890   g_object_freeze_notify (obj);
3891
3892   switch (axis)
3893     {
3894     case CLUTTER_X_AXIS:
3895       info->rx_angle = angle;
3896       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3897       break;
3898
3899     case CLUTTER_Y_AXIS:
3900       info->ry_angle = angle;
3901       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3902       break;
3903
3904     case CLUTTER_Z_AXIS:
3905       info->rz_angle = angle;
3906       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3907       break;
3908     }
3909
3910   self->priv->transform_valid = FALSE;
3911
3912   g_object_thaw_notify (obj);
3913
3914   clutter_actor_queue_redraw (self);
3915 }
3916
3917 static inline void
3918 clutter_actor_set_rotation_angle (ClutterActor      *self,
3919                                   ClutterRotateAxis  axis,
3920                                   gdouble            angle)
3921 {
3922   ClutterTransformInfo *info;
3923
3924   info = _clutter_actor_get_transform_info (self);
3925
3926   if (clutter_actor_get_easing_duration (self) != 0)
3927     {
3928       ClutterTransition *transition;
3929       GParamSpec *pspec = NULL;
3930       double *cur_angle_p = NULL;
3931
3932       switch (axis)
3933         {
3934         case CLUTTER_X_AXIS:
3935           cur_angle_p = &info->rx_angle;
3936           pspec = obj_props[PROP_ROTATION_ANGLE_X];
3937           break;
3938
3939         case CLUTTER_Y_AXIS:
3940           cur_angle_p = &info->ry_angle;
3941           pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3942           break;
3943
3944         case CLUTTER_Z_AXIS:
3945           cur_angle_p = &info->rz_angle;
3946           pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3947           break;
3948         }
3949
3950       g_assert (pspec != NULL);
3951       g_assert (cur_angle_p != NULL);
3952
3953       transition = _clutter_actor_get_transition (self, pspec);
3954       if (transition == NULL)
3955         {
3956           transition = _clutter_actor_create_transition (self, pspec,
3957                                                          *cur_angle_p,
3958                                                          angle);
3959           clutter_timeline_start (CLUTTER_TIMELINE (transition));
3960         }
3961       else
3962         _clutter_actor_update_transition (self, pspec, angle);
3963
3964       self->priv->transform_valid = FALSE;
3965       clutter_actor_queue_redraw (self);
3966     }
3967   else
3968     clutter_actor_set_rotation_angle_internal (self, axis, angle);
3969 }
3970
3971 /*< private >
3972  * clutter_actor_set_rotation_center_internal:
3973  * @self: a #ClutterActor
3974  * @axis: the axis of the center to change
3975  * @center: the coordinates of the rotation center
3976  *
3977  * Sets the rotation center on the given axis without affecting the
3978  * rotation angle.
3979  */
3980 static inline void
3981 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3982                                             ClutterRotateAxis    axis,
3983                                             const ClutterVertex *center)
3984 {
3985   GObject *obj = G_OBJECT (self);
3986   ClutterTransformInfo *info;
3987   ClutterVertex v = { 0, 0, 0 };
3988
3989   info = _clutter_actor_get_transform_info (self);
3990
3991   if (center != NULL)
3992     v = *center;
3993
3994   g_object_freeze_notify (obj);
3995
3996   switch (axis)
3997     {
3998     case CLUTTER_X_AXIS:
3999       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4000       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4001       break;
4002
4003     case CLUTTER_Y_AXIS:
4004       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4005       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4006       break;
4007
4008     case CLUTTER_Z_AXIS:
4009       /* if the previously set rotation center was fractional, then
4010        * setting explicit coordinates will have to notify the
4011        * :rotation-center-z-gravity property as well
4012        */
4013       if (info->rz_center.is_fractional)
4014         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4015
4016       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4018       break;
4019     }
4020
4021   self->priv->transform_valid = FALSE;
4022
4023   g_object_thaw_notify (obj);
4024
4025   clutter_actor_queue_redraw (self);
4026 }
4027
4028 static void
4029 clutter_actor_animate_scale_factor (ClutterActor *self,
4030                                     double        old_factor,
4031                                     double        new_factor,
4032                                     GParamSpec   *pspec)
4033 {
4034   ClutterTransition *transition;
4035
4036   transition = _clutter_actor_get_transition (self, pspec);
4037   if (transition == NULL)
4038     {
4039       transition = _clutter_actor_create_transition (self, pspec,
4040                                                      old_factor,
4041                                                      new_factor);
4042       clutter_timeline_start (CLUTTER_TIMELINE (transition));
4043     }
4044   else
4045     _clutter_actor_update_transition (self, pspec, new_factor);
4046
4047
4048   self->priv->transform_valid = FALSE;
4049   clutter_actor_queue_redraw (self);
4050 }
4051
4052 static void
4053 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4054                                          double factor,
4055                                          GParamSpec *pspec)
4056 {
4057   GObject *obj = G_OBJECT (self);
4058   ClutterTransformInfo *info;
4059
4060   info = _clutter_actor_get_transform_info (self);
4061
4062   if (pspec == obj_props[PROP_SCALE_X])
4063     info->scale_x = factor;
4064   else
4065     info->scale_y = factor;
4066
4067   self->priv->transform_valid = FALSE;
4068   clutter_actor_queue_redraw (self);
4069   g_object_notify_by_pspec (obj, pspec);
4070 }
4071
4072 static inline void
4073 clutter_actor_set_scale_factor (ClutterActor      *self,
4074                                 ClutterRotateAxis  axis,
4075                                 gdouble            factor)
4076 {
4077   GObject *obj = G_OBJECT (self);
4078   ClutterTransformInfo *info;
4079   GParamSpec *pspec;
4080
4081   info = _clutter_actor_get_transform_info (self);
4082
4083   g_object_freeze_notify (obj);
4084
4085   switch (axis)
4086     {
4087     case CLUTTER_X_AXIS:
4088       pspec = obj_props[PROP_SCALE_X];
4089
4090       if (clutter_actor_get_easing_duration (self) != 0)
4091         clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4092       else
4093         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4094       break;
4095
4096     case CLUTTER_Y_AXIS:
4097       pspec = obj_props[PROP_SCALE_Y];
4098
4099       if (clutter_actor_get_easing_duration (self) != 0)
4100         clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4101       else
4102         clutter_actor_set_scale_factor_internal (self, factor, pspec);
4103       break;
4104
4105     default:
4106       g_assert_not_reached ();
4107     }
4108
4109   g_object_thaw_notify (obj);
4110 }
4111
4112 static inline void
4113 clutter_actor_set_scale_center (ClutterActor      *self,
4114                                 ClutterRotateAxis  axis,
4115                                 gfloat             coord)
4116 {
4117   GObject *obj = G_OBJECT (self);
4118   ClutterTransformInfo *info;
4119   gfloat center_x, center_y;
4120
4121   info = _clutter_actor_get_transform_info (self);
4122
4123   g_object_freeze_notify (obj);
4124
4125   /* get the current scale center coordinates */
4126   clutter_anchor_coord_get_units (self, &info->scale_center,
4127                                   &center_x,
4128                                   &center_y,
4129                                   NULL);
4130
4131   /* we need to notify this too, because setting explicit coordinates will
4132    * change the gravity as a side effect
4133    */
4134   if (info->scale_center.is_fractional)
4135     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4136
4137   switch (axis)
4138     {
4139     case CLUTTER_X_AXIS:
4140       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4141       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4142       break;
4143
4144     case CLUTTER_Y_AXIS:
4145       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4146       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4147       break;
4148
4149     default:
4150       g_assert_not_reached ();
4151     }
4152
4153   self->priv->transform_valid = FALSE;
4154
4155   clutter_actor_queue_redraw (self);
4156
4157   g_object_thaw_notify (obj);
4158 }
4159
4160 static inline void
4161 clutter_actor_set_scale_gravity (ClutterActor   *self,
4162                                  ClutterGravity  gravity)
4163 {
4164   ClutterTransformInfo *info;
4165   GObject *obj;
4166
4167   info = _clutter_actor_get_transform_info (self);
4168   obj = G_OBJECT (self);
4169
4170   if (gravity == CLUTTER_GRAVITY_NONE)
4171     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4172   else
4173     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4174
4175   self->priv->transform_valid = FALSE;
4176
4177   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4178   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4179   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4180
4181   clutter_actor_queue_redraw (self);
4182 }
4183
4184 static inline void
4185 clutter_actor_set_anchor_coord (ClutterActor      *self,
4186                                 ClutterRotateAxis  axis,
4187                                 gfloat             coord)
4188 {
4189   GObject *obj = G_OBJECT (self);
4190   ClutterTransformInfo *info;
4191   gfloat anchor_x, anchor_y;
4192
4193   info = _clutter_actor_get_transform_info (self);
4194
4195   g_object_freeze_notify (obj);
4196
4197   clutter_anchor_coord_get_units (self, &info->anchor,
4198                                   &anchor_x,
4199                                   &anchor_y,
4200                                   NULL);
4201
4202   if (info->anchor.is_fractional)
4203     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4204
4205   switch (axis)
4206     {
4207     case CLUTTER_X_AXIS:
4208       clutter_anchor_coord_set_units (&info->anchor,
4209                                       coord,
4210                                       anchor_y,
4211                                       0.0);
4212       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4213       break;
4214
4215     case CLUTTER_Y_AXIS:
4216       clutter_anchor_coord_set_units (&info->anchor,
4217                                       anchor_x,
4218                                       coord,
4219                                       0.0);
4220       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4221       break;
4222
4223     default:
4224       g_assert_not_reached ();
4225     }
4226
4227   self->priv->transform_valid = FALSE;
4228
4229   clutter_actor_queue_redraw (self);
4230
4231   g_object_thaw_notify (obj);
4232 }
4233
4234 static void
4235 clutter_actor_set_property (GObject      *object,
4236                             guint         prop_id,
4237                             const GValue *value,
4238                             GParamSpec   *pspec)
4239 {
4240   ClutterActor *actor = CLUTTER_ACTOR (object);
4241   ClutterActorPrivate *priv = actor->priv;
4242
4243   switch (prop_id)
4244     {
4245     case PROP_X:
4246       clutter_actor_set_x (actor, g_value_get_float (value));
4247       break;
4248
4249     case PROP_Y:
4250       clutter_actor_set_y (actor, g_value_get_float (value));
4251       break;
4252
4253     case PROP_WIDTH:
4254       clutter_actor_set_width (actor, g_value_get_float (value));
4255       break;
4256
4257     case PROP_HEIGHT:
4258       clutter_actor_set_height (actor, g_value_get_float (value));
4259       break;
4260
4261     case PROP_FIXED_X:
4262       clutter_actor_set_x (actor, g_value_get_float (value));
4263       break;
4264
4265     case PROP_FIXED_Y:
4266       clutter_actor_set_y (actor, g_value_get_float (value));
4267       break;
4268
4269     case PROP_FIXED_POSITION_SET:
4270       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4271       break;
4272
4273     case PROP_MIN_WIDTH:
4274       clutter_actor_set_min_width (actor, g_value_get_float (value));
4275       break;
4276
4277     case PROP_MIN_HEIGHT:
4278       clutter_actor_set_min_height (actor, g_value_get_float (value));
4279       break;
4280
4281     case PROP_NATURAL_WIDTH:
4282       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4283       break;
4284
4285     case PROP_NATURAL_HEIGHT:
4286       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4287       break;
4288
4289     case PROP_MIN_WIDTH_SET:
4290       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4291       break;
4292
4293     case PROP_MIN_HEIGHT_SET:
4294       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4295       break;
4296
4297     case PROP_NATURAL_WIDTH_SET:
4298       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4299       break;
4300
4301     case PROP_NATURAL_HEIGHT_SET:
4302       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4303       break;
4304
4305     case PROP_REQUEST_MODE:
4306       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4307       break;
4308
4309     case PROP_DEPTH:
4310       clutter_actor_set_depth (actor, g_value_get_float (value));
4311       break;
4312
4313     case PROP_OPACITY:
4314       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4315       break;
4316
4317     case PROP_OFFSCREEN_REDIRECT:
4318       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4319       break;
4320
4321     case PROP_NAME:
4322       clutter_actor_set_name (actor, g_value_get_string (value));
4323       break;
4324
4325     case PROP_VISIBLE:
4326       if (g_value_get_boolean (value) == TRUE)
4327         clutter_actor_show (actor);
4328       else
4329         clutter_actor_hide (actor);
4330       break;
4331
4332     case PROP_SCALE_X:
4333       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4334                                       g_value_get_double (value));
4335       break;
4336
4337     case PROP_SCALE_Y:
4338       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4339                                       g_value_get_double (value));
4340       break;
4341
4342     case PROP_SCALE_CENTER_X:
4343       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4344                                       g_value_get_float (value));
4345       break;
4346
4347     case PROP_SCALE_CENTER_Y:
4348       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4349                                       g_value_get_float (value));
4350       break;
4351
4352     case PROP_SCALE_GRAVITY:
4353       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4354       break;
4355
4356     case PROP_CLIP:
4357       {
4358         const ClutterGeometry *geom = g_value_get_boxed (value);
4359
4360         clutter_actor_set_clip (actor,
4361                                 geom->x, geom->y,
4362                                 geom->width, geom->height);
4363       }
4364       break;
4365
4366     case PROP_CLIP_TO_ALLOCATION:
4367       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4368       break;
4369
4370     case PROP_REACTIVE:
4371       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4372       break;
4373
4374     case PROP_ROTATION_ANGLE_X:
4375       clutter_actor_set_rotation_angle (actor,
4376                                         CLUTTER_X_AXIS,
4377                                         g_value_get_double (value));
4378       break;
4379
4380     case PROP_ROTATION_ANGLE_Y:
4381       clutter_actor_set_rotation_angle (actor,
4382                                         CLUTTER_Y_AXIS,
4383                                         g_value_get_double (value));
4384       break;
4385
4386     case PROP_ROTATION_ANGLE_Z:
4387       clutter_actor_set_rotation_angle (actor,
4388                                         CLUTTER_Z_AXIS,
4389                                         g_value_get_double (value));
4390       break;
4391
4392     case PROP_ROTATION_CENTER_X:
4393       clutter_actor_set_rotation_center_internal (actor,
4394                                                   CLUTTER_X_AXIS,
4395                                                   g_value_get_boxed (value));
4396       break;
4397
4398     case PROP_ROTATION_CENTER_Y:
4399       clutter_actor_set_rotation_center_internal (actor,
4400                                                   CLUTTER_Y_AXIS,
4401                                                   g_value_get_boxed (value));
4402       break;
4403
4404     case PROP_ROTATION_CENTER_Z:
4405       clutter_actor_set_rotation_center_internal (actor,
4406                                                   CLUTTER_Z_AXIS,
4407                                                   g_value_get_boxed (value));
4408       break;
4409
4410     case PROP_ROTATION_CENTER_Z_GRAVITY:
4411       {
4412         const ClutterTransformInfo *info;
4413
4414         info = _clutter_actor_get_transform_info_or_defaults (actor);
4415         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4416                                                    g_value_get_enum (value));
4417       }
4418       break;
4419
4420     case PROP_ANCHOR_X:
4421       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4422                                       g_value_get_float (value));
4423       break;
4424
4425     case PROP_ANCHOR_Y:
4426       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4427                                       g_value_get_float (value));
4428       break;
4429
4430     case PROP_ANCHOR_GRAVITY:
4431       clutter_actor_set_anchor_point_from_gravity (actor,
4432                                                    g_value_get_enum (value));
4433       break;
4434
4435     case PROP_SHOW_ON_SET_PARENT:
4436       priv->show_on_set_parent = g_value_get_boolean (value);
4437       break;
4438
4439     case PROP_TEXT_DIRECTION:
4440       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4441       break;
4442
4443     case PROP_ACTIONS:
4444       clutter_actor_add_action (actor, g_value_get_object (value));
4445       break;
4446
4447     case PROP_CONSTRAINTS:
4448       clutter_actor_add_constraint (actor, g_value_get_object (value));
4449       break;
4450
4451     case PROP_EFFECT:
4452       clutter_actor_add_effect (actor, g_value_get_object (value));
4453       break;
4454
4455     case PROP_LAYOUT_MANAGER:
4456       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4457       break;
4458
4459     case PROP_X_ALIGN:
4460       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4461       break;
4462
4463     case PROP_Y_ALIGN:
4464       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4465       break;
4466
4467     case PROP_MARGIN_TOP:
4468       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4469       break;
4470
4471     case PROP_MARGIN_BOTTOM:
4472       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4473       break;
4474
4475     case PROP_MARGIN_LEFT:
4476       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4477       break;
4478
4479     case PROP_MARGIN_RIGHT:
4480       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4481       break;
4482
4483     case PROP_BACKGROUND_COLOR:
4484       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4485       break;
4486
4487     case PROP_CONTENT:
4488       clutter_actor_set_content (actor, g_value_get_object (value));
4489       break;
4490
4491     case PROP_CONTENT_GRAVITY:
4492       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4493       break;
4494
4495     case PROP_MINIFICATION_FILTER:
4496       clutter_actor_set_content_scaling_filters (actor,
4497                                                  g_value_get_enum (value),
4498                                                  actor->priv->mag_filter);
4499       break;
4500
4501     case PROP_MAGNIFICATION_FILTER:
4502       clutter_actor_set_content_scaling_filters (actor,
4503                                                  actor->priv->min_filter,
4504                                                  g_value_get_enum (value));
4505       break;
4506
4507     default:
4508       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4509       break;
4510     }
4511 }
4512
4513 static void
4514 clutter_actor_get_property (GObject    *object,
4515                             guint       prop_id,
4516                             GValue     *value,
4517                             GParamSpec *pspec)
4518 {
4519   ClutterActor *actor = CLUTTER_ACTOR (object);
4520   ClutterActorPrivate *priv = actor->priv;
4521
4522   switch (prop_id)
4523     {
4524     case PROP_X:
4525       g_value_set_float (value, clutter_actor_get_x (actor));
4526       break;
4527
4528     case PROP_Y:
4529       g_value_set_float (value, clutter_actor_get_y (actor));
4530       break;
4531
4532     case PROP_WIDTH:
4533       g_value_set_float (value, clutter_actor_get_width (actor));
4534       break;
4535
4536     case PROP_HEIGHT:
4537       g_value_set_float (value, clutter_actor_get_height (actor));
4538       break;
4539
4540     case PROP_FIXED_X:
4541       {
4542         const ClutterLayoutInfo *info;
4543
4544         info = _clutter_actor_get_layout_info_or_defaults (actor);
4545         g_value_set_float (value, info->fixed_x);
4546       }
4547       break;
4548
4549     case PROP_FIXED_Y:
4550       {
4551         const ClutterLayoutInfo *info;
4552
4553         info = _clutter_actor_get_layout_info_or_defaults (actor);
4554         g_value_set_float (value, info->fixed_y);
4555       }
4556       break;
4557
4558     case PROP_FIXED_POSITION_SET:
4559       g_value_set_boolean (value, priv->position_set);
4560       break;
4561
4562     case PROP_MIN_WIDTH:
4563       {
4564         const ClutterLayoutInfo *info;
4565
4566         info = _clutter_actor_get_layout_info_or_defaults (actor);
4567         g_value_set_float (value, info->min_width);
4568       }
4569       break;
4570
4571     case PROP_MIN_HEIGHT:
4572       {
4573         const ClutterLayoutInfo *info;
4574
4575         info = _clutter_actor_get_layout_info_or_defaults (actor);
4576         g_value_set_float (value, info->min_height);
4577       }
4578       break;
4579
4580     case PROP_NATURAL_WIDTH:
4581       {
4582         const ClutterLayoutInfo *info;
4583
4584         info = _clutter_actor_get_layout_info_or_defaults (actor);
4585         g_value_set_float (value, info->natural_width);
4586       }
4587       break;
4588
4589     case PROP_NATURAL_HEIGHT:
4590       {
4591         const ClutterLayoutInfo *info;
4592
4593         info = _clutter_actor_get_layout_info_or_defaults (actor);
4594         g_value_set_float (value, info->natural_height);
4595       }
4596       break;
4597
4598     case PROP_MIN_WIDTH_SET:
4599       g_value_set_boolean (value, priv->min_width_set);
4600       break;
4601
4602     case PROP_MIN_HEIGHT_SET:
4603       g_value_set_boolean (value, priv->min_height_set);
4604       break;
4605
4606     case PROP_NATURAL_WIDTH_SET:
4607       g_value_set_boolean (value, priv->natural_width_set);
4608       break;
4609
4610     case PROP_NATURAL_HEIGHT_SET:
4611       g_value_set_boolean (value, priv->natural_height_set);
4612       break;
4613
4614     case PROP_REQUEST_MODE:
4615       g_value_set_enum (value, priv->request_mode);
4616       break;
4617
4618     case PROP_ALLOCATION:
4619       g_value_set_boxed (value, &priv->allocation);
4620       break;
4621
4622     case PROP_DEPTH:
4623       g_value_set_float (value, clutter_actor_get_depth (actor));
4624       break;
4625
4626     case PROP_OPACITY:
4627       g_value_set_uint (value, priv->opacity);
4628       break;
4629
4630     case PROP_OFFSCREEN_REDIRECT:
4631       g_value_set_enum (value, priv->offscreen_redirect);
4632       break;
4633
4634     case PROP_NAME:
4635       g_value_set_string (value, priv->name);
4636       break;
4637
4638     case PROP_VISIBLE:
4639       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4640       break;
4641
4642     case PROP_MAPPED:
4643       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4644       break;
4645
4646     case PROP_REALIZED:
4647       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4648       break;
4649
4650     case PROP_HAS_CLIP:
4651       g_value_set_boolean (value, priv->has_clip);
4652       break;
4653
4654     case PROP_CLIP:
4655       {
4656         ClutterGeometry clip;
4657
4658         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4659         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4660         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4661         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4662
4663         g_value_set_boxed (value, &clip);
4664       }
4665       break;
4666
4667     case PROP_CLIP_TO_ALLOCATION:
4668       g_value_set_boolean (value, priv->clip_to_allocation);
4669       break;
4670
4671     case PROP_SCALE_X:
4672       {
4673         const ClutterTransformInfo *info;
4674
4675         info = _clutter_actor_get_transform_info_or_defaults (actor);
4676         g_value_set_double (value, info->scale_x);
4677       }
4678       break;
4679
4680     case PROP_SCALE_Y:
4681       {
4682         const ClutterTransformInfo *info;
4683
4684         info = _clutter_actor_get_transform_info_or_defaults (actor);
4685         g_value_set_double (value, info->scale_y);
4686       }
4687       break;
4688
4689     case PROP_SCALE_CENTER_X:
4690       {
4691         gfloat center;
4692
4693         clutter_actor_get_scale_center (actor, &center, NULL);
4694
4695         g_value_set_float (value, center);
4696       }
4697       break;
4698
4699     case PROP_SCALE_CENTER_Y:
4700       {
4701         gfloat center;
4702
4703         clutter_actor_get_scale_center (actor, NULL, &center);
4704
4705         g_value_set_float (value, center);
4706       }
4707       break;
4708
4709     case PROP_SCALE_GRAVITY:
4710       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4711       break;
4712
4713     case PROP_REACTIVE:
4714       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4715       break;
4716
4717     case PROP_ROTATION_ANGLE_X:
4718       {
4719         const ClutterTransformInfo *info;
4720
4721         info = _clutter_actor_get_transform_info_or_defaults (actor);
4722         g_value_set_double (value, info->rx_angle);
4723       }
4724       break;
4725
4726     case PROP_ROTATION_ANGLE_Y:
4727       {
4728         const ClutterTransformInfo *info;
4729
4730         info = _clutter_actor_get_transform_info_or_defaults (actor);
4731         g_value_set_double (value, info->ry_angle);
4732       }
4733       break;
4734
4735     case PROP_ROTATION_ANGLE_Z:
4736       {
4737         const ClutterTransformInfo *info;
4738
4739         info = _clutter_actor_get_transform_info_or_defaults (actor);
4740         g_value_set_double (value, info->rz_angle);
4741       }
4742       break;
4743
4744     case PROP_ROTATION_CENTER_X:
4745       {
4746         ClutterVertex center;
4747
4748         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4749                                     &center.x,
4750                                     &center.y,
4751                                     &center.z);
4752
4753         g_value_set_boxed (value, &center);
4754       }
4755       break;
4756
4757     case PROP_ROTATION_CENTER_Y:
4758       {
4759         ClutterVertex center;
4760
4761         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4762                                     &center.x,
4763                                     &center.y,
4764                                     &center.z);
4765
4766         g_value_set_boxed (value, &center);
4767       }
4768       break;
4769
4770     case PROP_ROTATION_CENTER_Z:
4771       {
4772         ClutterVertex center;
4773
4774         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4775                                     &center.x,
4776                                     &center.y,
4777                                     &center.z);
4778
4779         g_value_set_boxed (value, &center);
4780       }
4781       break;
4782
4783     case PROP_ROTATION_CENTER_Z_GRAVITY:
4784       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4785       break;
4786
4787     case PROP_ANCHOR_X:
4788       {
4789         const ClutterTransformInfo *info;
4790         gfloat anchor_x;
4791
4792         info = _clutter_actor_get_transform_info_or_defaults (actor);
4793         clutter_anchor_coord_get_units (actor, &info->anchor,
4794                                         &anchor_x,
4795                                         NULL,
4796                                         NULL);
4797         g_value_set_float (value, anchor_x);
4798       }
4799       break;
4800
4801     case PROP_ANCHOR_Y:
4802       {
4803         const ClutterTransformInfo *info;
4804         gfloat anchor_y;
4805
4806         info = _clutter_actor_get_transform_info_or_defaults (actor);
4807         clutter_anchor_coord_get_units (actor, &info->anchor,
4808                                         NULL,
4809                                         &anchor_y,
4810                                         NULL);
4811         g_value_set_float (value, anchor_y);
4812       }
4813       break;
4814
4815     case PROP_ANCHOR_GRAVITY:
4816       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4817       break;
4818
4819     case PROP_SHOW_ON_SET_PARENT:
4820       g_value_set_boolean (value, priv->show_on_set_parent);
4821       break;
4822
4823     case PROP_TEXT_DIRECTION:
4824       g_value_set_enum (value, priv->text_direction);
4825       break;
4826
4827     case PROP_HAS_POINTER:
4828       g_value_set_boolean (value, priv->has_pointer);
4829       break;
4830
4831     case PROP_LAYOUT_MANAGER:
4832       g_value_set_object (value, priv->layout_manager);
4833       break;
4834
4835     case PROP_X_ALIGN:
4836       {
4837         const ClutterLayoutInfo *info;
4838
4839         info = _clutter_actor_get_layout_info_or_defaults (actor);
4840         g_value_set_enum (value, info->x_align);
4841       }
4842       break;
4843
4844     case PROP_Y_ALIGN:
4845       {
4846         const ClutterLayoutInfo *info;
4847
4848         info = _clutter_actor_get_layout_info_or_defaults (actor);
4849         g_value_set_enum (value, info->y_align);
4850       }
4851       break;
4852
4853     case PROP_MARGIN_TOP:
4854       {
4855         const ClutterLayoutInfo *info;
4856
4857         info = _clutter_actor_get_layout_info_or_defaults (actor);
4858         g_value_set_float (value, info->margin.top);
4859       }
4860       break;
4861
4862     case PROP_MARGIN_BOTTOM:
4863       {
4864         const ClutterLayoutInfo *info;
4865
4866         info = _clutter_actor_get_layout_info_or_defaults (actor);
4867         g_value_set_float (value, info->margin.bottom);
4868       }
4869       break;
4870
4871     case PROP_MARGIN_LEFT:
4872       {
4873         const ClutterLayoutInfo *info;
4874
4875         info = _clutter_actor_get_layout_info_or_defaults (actor);
4876         g_value_set_float (value, info->margin.left);
4877       }
4878       break;
4879
4880     case PROP_MARGIN_RIGHT:
4881       {
4882         const ClutterLayoutInfo *info;
4883
4884         info = _clutter_actor_get_layout_info_or_defaults (actor);
4885         g_value_set_float (value, info->margin.right);
4886       }
4887       break;
4888
4889     case PROP_BACKGROUND_COLOR_SET:
4890       g_value_set_boolean (value, priv->bg_color_set);
4891       break;
4892
4893     case PROP_BACKGROUND_COLOR:
4894       g_value_set_boxed (value, &priv->bg_color);
4895       break;
4896
4897     case PROP_FIRST_CHILD:
4898       g_value_set_object (value, priv->first_child);
4899       break;
4900
4901     case PROP_LAST_CHILD:
4902       g_value_set_object (value, priv->last_child);
4903       break;
4904
4905     case PROP_CONTENT:
4906       g_value_set_object (value, priv->content);
4907       break;
4908
4909     case PROP_CONTENT_GRAVITY:
4910       g_value_set_enum (value, priv->content_gravity);
4911       break;
4912
4913     case PROP_CONTENT_BOX:
4914       {
4915         ClutterActorBox box = { 0, };
4916
4917         clutter_actor_get_content_box (actor, &box);
4918         g_value_set_boxed (value, &box);
4919       }
4920       break;
4921
4922     case PROP_MINIFICATION_FILTER:
4923       g_value_set_enum (value, priv->min_filter);
4924       break;
4925
4926     case PROP_MAGNIFICATION_FILTER:
4927       g_value_set_enum (value, priv->mag_filter);
4928       break;
4929
4930     default:
4931       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4932       break;
4933     }
4934 }
4935
4936 static void
4937 clutter_actor_dispose (GObject *object)
4938 {
4939   ClutterActor *self = CLUTTER_ACTOR (object);
4940   ClutterActorPrivate *priv = self->priv;
4941
4942   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4943                 priv->id,
4944                 g_type_name (G_OBJECT_TYPE (self)),
4945                 object->ref_count);
4946
4947   g_signal_emit (self, actor_signals[DESTROY], 0);
4948
4949   /* avoid recursing when called from clutter_actor_destroy() */
4950   if (priv->parent != NULL)
4951     {
4952       ClutterActor *parent = priv->parent;
4953
4954       /* go through the Container implementation unless this
4955        * is an internal child and has been marked as such.
4956        *
4957        * removing the actor from its parent will reset the
4958        * realized and mapped states.
4959        */
4960       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4961         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4962       else
4963         clutter_actor_remove_child_internal (parent, self,
4964                                              REMOVE_CHILD_LEGACY_FLAGS);
4965     }
4966
4967   /* parent must be gone at this point */
4968   g_assert (priv->parent == NULL);
4969
4970   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4971     {
4972       /* can't be mapped or realized with no parent */
4973       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4974       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4975     }
4976
4977   g_clear_object (&priv->pango_context);
4978   g_clear_object (&priv->actions);
4979   g_clear_object (&priv->constraints);
4980   g_clear_object (&priv->effects);
4981   g_clear_object (&priv->flatten_effect);
4982
4983   if (priv->layout_manager != NULL)
4984     {
4985       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4986       g_clear_object (&priv->layout_manager);
4987     }
4988
4989   if (priv->content != NULL)
4990     {
4991       _clutter_content_detached (priv->content, self);
4992       g_clear_object (&priv->content);
4993     }
4994
4995   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4996 }
4997
4998 static void
4999 clutter_actor_finalize (GObject *object)
5000 {
5001   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5002
5003   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5004                 priv->name != NULL ? priv->name : "<none>",
5005                 priv->id,
5006                 g_type_name (G_OBJECT_TYPE (object)));
5007
5008   _clutter_context_release_id (priv->id);
5009
5010   g_free (priv->name);
5011
5012   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5013 }
5014
5015
5016 /**
5017  * clutter_actor_get_accessible:
5018  * @self: a #ClutterActor
5019  *
5020  * Returns the accessible object that describes the actor to an
5021  * assistive technology.
5022  *
5023  * If no class-specific #AtkObject implementation is available for the
5024  * actor instance in question, it will inherit an #AtkObject
5025  * implementation from the first ancestor class for which such an
5026  * implementation is defined.
5027  *
5028  * The documentation of the <ulink
5029  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5030  * library contains more information about accessible objects and
5031  * their uses.
5032  *
5033  * Returns: (transfer none): the #AtkObject associated with @actor
5034  */
5035 AtkObject *
5036 clutter_actor_get_accessible (ClutterActor *self)
5037 {
5038   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5039
5040   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5041 }
5042
5043 static AtkObject *
5044 clutter_actor_real_get_accessible (ClutterActor *actor)
5045 {
5046   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5047 }
5048
5049 static AtkObject *
5050 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5051 {
5052   AtkObject *accessible;
5053
5054   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5055   if (accessible != NULL)
5056     g_object_ref (accessible);
5057
5058   return accessible;
5059 }
5060
5061 static void
5062 atk_implementor_iface_init (AtkImplementorIface *iface)
5063 {
5064   iface->ref_accessible = _clutter_actor_ref_accessible;
5065 }
5066
5067 static gboolean
5068 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5069                                            ClutterPaintVolume *volume)
5070 {
5071   ClutterActorPrivate *priv = self->priv;
5072   gboolean res = FALSE;
5073
5074   /* we start from the allocation */
5075   clutter_paint_volume_set_width (volume,
5076                                   priv->allocation.x2 - priv->allocation.x1);
5077   clutter_paint_volume_set_height (volume,
5078                                    priv->allocation.y2 - priv->allocation.y1);
5079
5080   /* if the actor has a clip set then we have a pretty definite
5081    * size for the paint volume: the actor cannot possibly paint
5082    * outside the clip region.
5083    */
5084   if (priv->clip_to_allocation)
5085     {
5086       /* the allocation has already been set, so we just flip the
5087        * return value
5088        */
5089       res = TRUE;
5090     }
5091   else
5092     {
5093       ClutterActor *child;
5094
5095       if (priv->has_clip &&
5096           priv->clip.width >= 0 &&
5097           priv->clip.height >= 0)
5098         {
5099           ClutterVertex origin;
5100
5101           origin.x = priv->clip.x;
5102           origin.y = priv->clip.y;
5103           origin.z = 0;
5104
5105           clutter_paint_volume_set_origin (volume, &origin);
5106           clutter_paint_volume_set_width (volume, priv->clip.width);
5107           clutter_paint_volume_set_height (volume, priv->clip.height);
5108
5109           res = TRUE;
5110         }
5111
5112       /* if we don't have children we just bail out here... */
5113       if (priv->n_children == 0)
5114         return res;
5115
5116       /* ...but if we have children then we ask for their paint volume in
5117        * our coordinates. if any of our children replies that it doesn't
5118        * have a paint volume, we bail out
5119        */
5120       for (child = priv->first_child;
5121            child != NULL;
5122            child = child->priv->next_sibling)
5123         {
5124           const ClutterPaintVolume *child_volume;
5125
5126           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5127           if (child_volume == NULL)
5128             {
5129               res = FALSE;
5130               break;
5131             }
5132
5133           clutter_paint_volume_union (volume, child_volume);
5134           res = TRUE;
5135         }
5136     }
5137
5138   return res;
5139
5140 }
5141
5142 static gboolean
5143 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5144                                      ClutterPaintVolume *volume)
5145 {
5146   ClutterActorClass *klass;
5147   gboolean res;
5148
5149   klass = CLUTTER_ACTOR_GET_CLASS (self);
5150
5151   /* XXX - this thoroughly sucks, but we don't want to penalize users
5152    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5153    * redraw. This should go away in 2.0.
5154    */
5155   if (klass->paint == clutter_actor_real_paint &&
5156       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5157     {
5158       res = TRUE;
5159     }
5160   else
5161     {
5162       /* this is the default return value: we cannot know if a class
5163        * is going to paint outside its allocation, so we take the
5164        * conservative approach.
5165        */
5166       res = FALSE;
5167     }
5168
5169   if (clutter_actor_update_default_paint_volume (self, volume))
5170     return res;
5171
5172   return FALSE;
5173 }
5174
5175 /**
5176  * clutter_actor_get_default_paint_volume:
5177  * @self: a #ClutterActor
5178  *
5179  * Retrieves the default paint volume for @self.
5180  *
5181  * This function provides the same #ClutterPaintVolume that would be
5182  * computed by the default implementation inside #ClutterActor of the
5183  * #ClutterActorClass.get_paint_volume() virtual function.
5184  *
5185  * This function should only be used by #ClutterActor subclasses that
5186  * cannot chain up to the parent implementation when computing their
5187  * paint volume.
5188  *
5189  * Return value: (transfer none): a pointer to the default
5190  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5191  *   the actor could not compute a valid paint volume. The returned value
5192  *   is not guaranteed to be stable across multiple frames, so if you
5193  *   want to retain it, you will need to copy it using
5194  *   clutter_paint_volume_copy().
5195  *
5196  * Since: 1.10
5197  */
5198 const ClutterPaintVolume *
5199 clutter_actor_get_default_paint_volume (ClutterActor *self)
5200 {
5201   ClutterPaintVolume volume;
5202   ClutterPaintVolume *res;
5203
5204   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5205
5206   res = NULL;
5207   _clutter_paint_volume_init_static (&volume, self);
5208   if (clutter_actor_update_default_paint_volume (self, &volume))
5209     {
5210       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5211
5212       if (stage != NULL)
5213         {
5214           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5215           _clutter_paint_volume_copy_static (&volume, res);
5216         }
5217     }
5218
5219   clutter_paint_volume_free (&volume);
5220
5221   return res;
5222 }
5223
5224 static gboolean
5225 clutter_actor_real_has_overlaps (ClutterActor *self)
5226 {
5227   /* By default we'll assume that all actors need an offscreen redirect to get
5228    * the correct opacity. Actors such as ClutterTexture that would never need
5229    * an offscreen redirect can override this to return FALSE. */
5230   return TRUE;
5231 }
5232
5233 static void
5234 clutter_actor_real_destroy (ClutterActor *actor)
5235 {
5236   ClutterActorIter iter;
5237
5238   clutter_actor_iter_init (&iter, actor);
5239   while (clutter_actor_iter_next (&iter, NULL))
5240     clutter_actor_iter_destroy (&iter);
5241 }
5242
5243 static GObject *
5244 clutter_actor_constructor (GType gtype,
5245                            guint n_props,
5246                            GObjectConstructParam *props)
5247 {
5248   GObjectClass *gobject_class;
5249   ClutterActor *self;
5250   GObject *retval;
5251
5252   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5253   retval = gobject_class->constructor (gtype, n_props, props);
5254   self = CLUTTER_ACTOR (retval);
5255
5256   if (self->priv->layout_manager == NULL)
5257     {
5258       ClutterLayoutManager *default_layout;
5259
5260       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5261
5262       default_layout = clutter_fixed_layout_new ();
5263       clutter_actor_set_layout_manager (self, default_layout);
5264     }
5265
5266   return retval;
5267 }
5268
5269 static void
5270 clutter_actor_class_init (ClutterActorClass *klass)
5271 {
5272   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5273
5274   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5275   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5276   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5277   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5278
5279   object_class->constructor = clutter_actor_constructor;
5280   object_class->set_property = clutter_actor_set_property;
5281   object_class->get_property = clutter_actor_get_property;
5282   object_class->dispose = clutter_actor_dispose;
5283   object_class->finalize = clutter_actor_finalize;
5284
5285   klass->show = clutter_actor_real_show;
5286   klass->show_all = clutter_actor_show;
5287   klass->hide = clutter_actor_real_hide;
5288   klass->hide_all = clutter_actor_hide;
5289   klass->map = clutter_actor_real_map;
5290   klass->unmap = clutter_actor_real_unmap;
5291   klass->unrealize = clutter_actor_real_unrealize;
5292   klass->pick = clutter_actor_real_pick;
5293   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5294   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5295   klass->allocate = clutter_actor_real_allocate;
5296   klass->queue_redraw = clutter_actor_real_queue_redraw;
5297   klass->queue_relayout = clutter_actor_real_queue_relayout;
5298   klass->apply_transform = clutter_actor_real_apply_transform;
5299   klass->get_accessible = clutter_actor_real_get_accessible;
5300   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5301   klass->has_overlaps = clutter_actor_real_has_overlaps;
5302   klass->paint = clutter_actor_real_paint;
5303   klass->destroy = clutter_actor_real_destroy;
5304
5305   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5306
5307   /**
5308    * ClutterActor:x:
5309    *
5310    * X coordinate of the actor in pixels. If written, forces a fixed
5311    * position for the actor. If read, returns the fixed position if any,
5312    * otherwise the allocation if available, otherwise 0.
5313    *
5314    * The #ClutterActor:x property is animatable.
5315    */
5316   obj_props[PROP_X] =
5317     g_param_spec_float ("x",
5318                         P_("X coordinate"),
5319                         P_("X coordinate of the actor"),
5320                         -G_MAXFLOAT, G_MAXFLOAT,
5321                         0.0,
5322                         G_PARAM_READWRITE |
5323                         G_PARAM_STATIC_STRINGS |
5324                         CLUTTER_PARAM_ANIMATABLE);
5325
5326   /**
5327    * ClutterActor:y:
5328    *
5329    * Y coordinate of the actor in pixels. If written, forces a fixed
5330    * position for the actor.  If read, returns the fixed position if
5331    * any, otherwise the allocation if available, otherwise 0.
5332    *
5333    * The #ClutterActor:y property is animatable.
5334    */
5335   obj_props[PROP_Y] =
5336     g_param_spec_float ("y",
5337                         P_("Y coordinate"),
5338                         P_("Y coordinate of the actor"),
5339                         -G_MAXFLOAT, G_MAXFLOAT,
5340                         0.0,
5341                         G_PARAM_READWRITE |
5342                         G_PARAM_STATIC_STRINGS |
5343                         CLUTTER_PARAM_ANIMATABLE);
5344
5345   /**
5346    * ClutterActor:width:
5347    *
5348    * Width of the actor (in pixels). If written, forces the minimum and
5349    * natural size request of the actor to the given width. If read, returns
5350    * the allocated width if available, otherwise the width request.
5351    *
5352    * The #ClutterActor:width property is animatable.
5353    */
5354   obj_props[PROP_WIDTH] =
5355     g_param_spec_float ("width",
5356                         P_("Width"),
5357                         P_("Width of the actor"),
5358                         0.0, G_MAXFLOAT,
5359                         0.0,
5360                         G_PARAM_READWRITE |
5361                         G_PARAM_STATIC_STRINGS |
5362                         CLUTTER_PARAM_ANIMATABLE);
5363
5364   /**
5365    * ClutterActor:height:
5366    *
5367    * Height of the actor (in pixels).  If written, forces the minimum and
5368    * natural size request of the actor to the given height. If read, returns
5369    * the allocated height if available, otherwise the height request.
5370    *
5371    * The #ClutterActor:height property is animatable.
5372    */
5373   obj_props[PROP_HEIGHT] =
5374     g_param_spec_float ("height",
5375                         P_("Height"),
5376                         P_("Height of the actor"),
5377                         0.0, G_MAXFLOAT,
5378                         0.0,
5379                         G_PARAM_READWRITE |
5380                         G_PARAM_STATIC_STRINGS |
5381                         CLUTTER_PARAM_ANIMATABLE);
5382
5383   /**
5384    * ClutterActor:fixed-x:
5385    *
5386    * The fixed X position of the actor in pixels.
5387    *
5388    * Writing this property sets #ClutterActor:fixed-position-set
5389    * property as well, as a side effect
5390    *
5391    * Since: 0.8
5392    */
5393   obj_props[PROP_FIXED_X] =
5394     g_param_spec_float ("fixed-x",
5395                         P_("Fixed X"),
5396                         P_("Forced X position of the actor"),
5397                         -G_MAXFLOAT, G_MAXFLOAT,
5398                         0.0,
5399                         CLUTTER_PARAM_READWRITE);
5400
5401   /**
5402    * ClutterActor:fixed-y:
5403    *
5404    * The fixed Y position of the actor in pixels.
5405    *
5406    * Writing this property sets the #ClutterActor:fixed-position-set
5407    * property as well, as a side effect
5408    *
5409    * Since: 0.8
5410    */
5411   obj_props[PROP_FIXED_Y] =
5412     g_param_spec_float ("fixed-y",
5413                         P_("Fixed Y"),
5414                         P_("Forced Y position of the actor"),
5415                         -G_MAXFLOAT, G_MAXFLOAT,
5416                         0,
5417                         CLUTTER_PARAM_READWRITE);
5418
5419   /**
5420    * ClutterActor:fixed-position-set:
5421    *
5422    * This flag controls whether the #ClutterActor:fixed-x and
5423    * #ClutterActor:fixed-y properties are used
5424    *
5425    * Since: 0.8
5426    */
5427   obj_props[PROP_FIXED_POSITION_SET] =
5428     g_param_spec_boolean ("fixed-position-set",
5429                           P_("Fixed position set"),
5430                           P_("Whether to use fixed positioning for the actor"),
5431                           FALSE,
5432                           CLUTTER_PARAM_READWRITE);
5433
5434   /**
5435    * ClutterActor:min-width:
5436    *
5437    * A forced minimum width request for the actor, in pixels
5438    *
5439    * Writing this property sets the #ClutterActor:min-width-set property
5440    * as well, as a side effect.
5441    *
5442    *This property overrides the usual width request of the actor.
5443    *
5444    * Since: 0.8
5445    */
5446   obj_props[PROP_MIN_WIDTH] =
5447     g_param_spec_float ("min-width",
5448                         P_("Min Width"),
5449                         P_("Forced minimum width request for the actor"),
5450                         0.0, G_MAXFLOAT,
5451                         0.0,
5452                         CLUTTER_PARAM_READWRITE);
5453
5454   /**
5455    * ClutterActor:min-height:
5456    *
5457    * A forced minimum height request for the actor, in pixels
5458    *
5459    * Writing this property sets the #ClutterActor:min-height-set property
5460    * as well, as a side effect. This property overrides the usual height
5461    * request of the actor.
5462    *
5463    * Since: 0.8
5464    */
5465   obj_props[PROP_MIN_HEIGHT] =
5466     g_param_spec_float ("min-height",
5467                         P_("Min Height"),
5468                         P_("Forced minimum height request for the actor"),
5469                         0.0, G_MAXFLOAT,
5470                         0.0,
5471                         CLUTTER_PARAM_READWRITE);
5472
5473   /**
5474    * ClutterActor:natural-width:
5475    *
5476    * A forced natural width request for the actor, in pixels
5477    *
5478    * Writing this property sets the #ClutterActor:natural-width-set
5479    * property as well, as a side effect. This property overrides the
5480    * usual width request of the actor
5481    *
5482    * Since: 0.8
5483    */
5484   obj_props[PROP_NATURAL_WIDTH] =
5485     g_param_spec_float ("natural-width",
5486                         P_("Natural Width"),
5487                         P_("Forced natural width request for the actor"),
5488                         0.0, G_MAXFLOAT,
5489                         0.0,
5490                         CLUTTER_PARAM_READWRITE);
5491
5492   /**
5493    * ClutterActor:natural-height:
5494    *
5495    * A forced natural height request for the actor, in pixels
5496    *
5497    * Writing this property sets the #ClutterActor:natural-height-set
5498    * property as well, as a side effect. This property overrides the
5499    * usual height request of the actor
5500    *
5501    * Since: 0.8
5502    */
5503   obj_props[PROP_NATURAL_HEIGHT] =
5504     g_param_spec_float ("natural-height",
5505                         P_("Natural Height"),
5506                         P_("Forced natural height request for the actor"),
5507                         0.0, G_MAXFLOAT,
5508                         0.0,
5509                         CLUTTER_PARAM_READWRITE);
5510
5511   /**
5512    * ClutterActor:min-width-set:
5513    *
5514    * This flag controls whether the #ClutterActor:min-width property
5515    * is used
5516    *
5517    * Since: 0.8
5518    */
5519   obj_props[PROP_MIN_WIDTH_SET] =
5520     g_param_spec_boolean ("min-width-set",
5521                           P_("Minimum width set"),
5522                           P_("Whether to use the min-width property"),
5523                           FALSE,
5524                           CLUTTER_PARAM_READWRITE);
5525
5526   /**
5527    * ClutterActor:min-height-set:
5528    *
5529    * This flag controls whether the #ClutterActor:min-height property
5530    * is used
5531    *
5532    * Since: 0.8
5533    */
5534   obj_props[PROP_MIN_HEIGHT_SET] =
5535     g_param_spec_boolean ("min-height-set",
5536                           P_("Minimum height set"),
5537                           P_("Whether to use the min-height property"),
5538                           FALSE,
5539                           CLUTTER_PARAM_READWRITE);
5540
5541   /**
5542    * ClutterActor:natural-width-set:
5543    *
5544    * This flag controls whether the #ClutterActor:natural-width property
5545    * is used
5546    *
5547    * Since: 0.8
5548    */
5549   obj_props[PROP_NATURAL_WIDTH_SET] =
5550     g_param_spec_boolean ("natural-width-set",
5551                           P_("Natural width set"),
5552                           P_("Whether to use the natural-width property"),
5553                           FALSE,
5554                           CLUTTER_PARAM_READWRITE);
5555
5556   /**
5557    * ClutterActor:natural-height-set:
5558    *
5559    * This flag controls whether the #ClutterActor:natural-height property
5560    * is used
5561    *
5562    * Since: 0.8
5563    */
5564   obj_props[PROP_NATURAL_HEIGHT_SET] =
5565     g_param_spec_boolean ("natural-height-set",
5566                           P_("Natural height set"),
5567                           P_("Whether to use the natural-height property"),
5568                           FALSE,
5569                           CLUTTER_PARAM_READWRITE);
5570
5571   /**
5572    * ClutterActor:allocation:
5573    *
5574    * The allocation for the actor, in pixels
5575    *
5576    * This is property is read-only, but you might monitor it to know when an
5577    * actor moves or resizes
5578    *
5579    * Since: 0.8
5580    */
5581   obj_props[PROP_ALLOCATION] =
5582     g_param_spec_boxed ("allocation",
5583                         P_("Allocation"),
5584                         P_("The actor's allocation"),
5585                         CLUTTER_TYPE_ACTOR_BOX,
5586                         CLUTTER_PARAM_READABLE);
5587
5588   /**
5589    * ClutterActor:request-mode:
5590    *
5591    * Request mode for the #ClutterActor. The request mode determines the
5592    * type of geometry management used by the actor, either height for width
5593    * (the default) or width for height.
5594    *
5595    * For actors implementing height for width, the parent container should get
5596    * the preferred width first, and then the preferred height for that width.
5597    *
5598    * For actors implementing width for height, the parent container should get
5599    * the preferred height first, and then the preferred width for that height.
5600    *
5601    * For instance:
5602    *
5603    * |[
5604    *   ClutterRequestMode mode;
5605    *   gfloat natural_width, min_width;
5606    *   gfloat natural_height, min_height;
5607    *
5608    *   mode = clutter_actor_get_request_mode (child);
5609    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5610    *     {
5611    *       clutter_actor_get_preferred_width (child, -1,
5612    *                                          &amp;min_width,
5613    *                                          &amp;natural_width);
5614    *       clutter_actor_get_preferred_height (child, natural_width,
5615    *                                           &amp;min_height,
5616    *                                           &amp;natural_height);
5617    *     }
5618    *   else
5619    *     {
5620    *       clutter_actor_get_preferred_height (child, -1,
5621    *                                           &amp;min_height,
5622    *                                           &amp;natural_height);
5623    *       clutter_actor_get_preferred_width (child, natural_height,
5624    *                                          &amp;min_width,
5625    *                                          &amp;natural_width);
5626    *     }
5627    * ]|
5628    *
5629    * will retrieve the minimum and natural width and height depending on the
5630    * preferred request mode of the #ClutterActor "child".
5631    *
5632    * The clutter_actor_get_preferred_size() function will implement this
5633    * check for you.
5634    *
5635    * Since: 0.8
5636    */
5637   obj_props[PROP_REQUEST_MODE] =
5638     g_param_spec_enum ("request-mode",
5639                        P_("Request Mode"),
5640                        P_("The actor's request mode"),
5641                        CLUTTER_TYPE_REQUEST_MODE,
5642                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5643                        CLUTTER_PARAM_READWRITE);
5644
5645   /**
5646    * ClutterActor:depth:
5647    *
5648    * The position of the actor on the Z axis.
5649    *
5650    * The #ClutterActor:depth property is relative to the parent's
5651    * modelview matrix.
5652    *
5653    * The #ClutterActor:depth property is animatable.
5654    *
5655    * Since: 0.6
5656    */
5657   obj_props[PROP_DEPTH] =
5658     g_param_spec_float ("depth",
5659                         P_("Depth"),
5660                         P_("Position on the Z axis"),
5661                         -G_MAXFLOAT, G_MAXFLOAT,
5662                         0.0,
5663                         G_PARAM_READWRITE |
5664                         G_PARAM_STATIC_STRINGS |
5665                         CLUTTER_PARAM_ANIMATABLE);
5666
5667   /**
5668    * ClutterActor:opacity:
5669    *
5670    * Opacity of an actor, between 0 (fully transparent) and
5671    * 255 (fully opaque)
5672    *
5673    * The #ClutterActor:opacity property is animatable.
5674    */
5675   obj_props[PROP_OPACITY] =
5676     g_param_spec_uint ("opacity",
5677                        P_("Opacity"),
5678                        P_("Opacity of an actor"),
5679                        0, 255,
5680                        255,
5681                        G_PARAM_READWRITE |
5682                        G_PARAM_STATIC_STRINGS |
5683                        CLUTTER_PARAM_ANIMATABLE);
5684
5685   /**
5686    * ClutterActor:offscreen-redirect:
5687    *
5688    * Determines the conditions in which the actor will be redirected
5689    * to an offscreen framebuffer while being painted. For example this
5690    * can be used to cache an actor in a framebuffer or for improved
5691    * handling of transparent actors. See
5692    * clutter_actor_set_offscreen_redirect() for details.
5693    *
5694    * Since: 1.8
5695    */
5696   obj_props[PROP_OFFSCREEN_REDIRECT] =
5697     g_param_spec_flags ("offscreen-redirect",
5698                         P_("Offscreen redirect"),
5699                         P_("Flags controlling when to flatten the actor into a single image"),
5700                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5701                         0,
5702                         CLUTTER_PARAM_READWRITE);
5703
5704   /**
5705    * ClutterActor:visible:
5706    *
5707    * Whether the actor is set to be visible or not
5708    *
5709    * See also #ClutterActor:mapped
5710    */
5711   obj_props[PROP_VISIBLE] =
5712     g_param_spec_boolean ("visible",
5713                           P_("Visible"),
5714                           P_("Whether the actor is visible or not"),
5715                           FALSE,
5716                           CLUTTER_PARAM_READWRITE);
5717
5718   /**
5719    * ClutterActor:mapped:
5720    *
5721    * Whether the actor is mapped (will be painted when the stage
5722    * to which it belongs is mapped)
5723    *
5724    * Since: 1.0
5725    */
5726   obj_props[PROP_MAPPED] =
5727     g_param_spec_boolean ("mapped",
5728                           P_("Mapped"),
5729                           P_("Whether the actor will be painted"),
5730                           FALSE,
5731                           CLUTTER_PARAM_READABLE);
5732
5733   /**
5734    * ClutterActor:realized:
5735    *
5736    * Whether the actor has been realized
5737    *
5738    * Since: 1.0
5739    */
5740   obj_props[PROP_REALIZED] =
5741     g_param_spec_boolean ("realized",
5742                           P_("Realized"),
5743                           P_("Whether the actor has been realized"),
5744                           FALSE,
5745                           CLUTTER_PARAM_READABLE);
5746
5747   /**
5748    * ClutterActor:reactive:
5749    *
5750    * Whether the actor is reactive to events or not
5751    *
5752    * Only reactive actors will emit event-related signals
5753    *
5754    * Since: 0.6
5755    */
5756   obj_props[PROP_REACTIVE] =
5757     g_param_spec_boolean ("reactive",
5758                           P_("Reactive"),
5759                           P_("Whether the actor is reactive to events"),
5760                           FALSE,
5761                           CLUTTER_PARAM_READWRITE);
5762
5763   /**
5764    * ClutterActor:has-clip:
5765    *
5766    * Whether the actor has the #ClutterActor:clip property set or not
5767    */
5768   obj_props[PROP_HAS_CLIP] =
5769     g_param_spec_boolean ("has-clip",
5770                           P_("Has Clip"),
5771                           P_("Whether the actor has a clip set"),
5772                           FALSE,
5773                           CLUTTER_PARAM_READABLE);
5774
5775   /**
5776    * ClutterActor:clip:
5777    *
5778    * The clip region for the actor, in actor-relative coordinates
5779    *
5780    * Every part of the actor outside the clip region will not be
5781    * painted
5782    */
5783   obj_props[PROP_CLIP] =
5784     g_param_spec_boxed ("clip",
5785                         P_("Clip"),
5786                         P_("The clip region for the actor"),
5787                         CLUTTER_TYPE_GEOMETRY,
5788                         CLUTTER_PARAM_READWRITE);
5789
5790   /**
5791    * ClutterActor:name:
5792    *
5793    * The name of the actor
5794    *
5795    * Since: 0.2
5796    */
5797   obj_props[PROP_NAME] =
5798     g_param_spec_string ("name",
5799                          P_("Name"),
5800                          P_("Name of the actor"),
5801                          NULL,
5802                          CLUTTER_PARAM_READWRITE);
5803
5804   /**
5805    * ClutterActor:scale-x:
5806    *
5807    * The horizontal scale of the actor.
5808    *
5809    * The #ClutterActor:scale-x property is animatable.
5810    *
5811    * Since: 0.6
5812    */
5813   obj_props[PROP_SCALE_X] =
5814     g_param_spec_double ("scale-x",
5815                          P_("Scale X"),
5816                          P_("Scale factor on the X axis"),
5817                          0.0, G_MAXDOUBLE,
5818                          1.0,
5819                          G_PARAM_READWRITE |
5820                          G_PARAM_STATIC_STRINGS |
5821                          CLUTTER_PARAM_ANIMATABLE);
5822
5823   /**
5824    * ClutterActor:scale-y:
5825    *
5826    * The vertical scale of the actor.
5827    *
5828    * The #ClutterActor:scale-y property is animatable.
5829    *
5830    * Since: 0.6
5831    */
5832   obj_props[PROP_SCALE_Y] =
5833     g_param_spec_double ("scale-y",
5834                          P_("Scale Y"),
5835                          P_("Scale factor on the Y axis"),
5836                          0.0, G_MAXDOUBLE,
5837                          1.0,
5838                          G_PARAM_READWRITE |
5839                          G_PARAM_STATIC_STRINGS |
5840                          CLUTTER_PARAM_ANIMATABLE);
5841
5842   /**
5843    * ClutterActor:scale-center-x:
5844    *
5845    * The horizontal center point for scaling
5846    *
5847    * Since: 1.0
5848    */
5849   obj_props[PROP_SCALE_CENTER_X] =
5850     g_param_spec_float ("scale-center-x",
5851                         P_("Scale Center X"),
5852                         P_("Horizontal scale center"),
5853                         -G_MAXFLOAT, G_MAXFLOAT,
5854                         0.0,
5855                         CLUTTER_PARAM_READWRITE);
5856
5857   /**
5858    * ClutterActor:scale-center-y:
5859    *
5860    * The vertical center point for scaling
5861    *
5862    * Since: 1.0
5863    */
5864   obj_props[PROP_SCALE_CENTER_Y] =
5865     g_param_spec_float ("scale-center-y",
5866                         P_("Scale Center Y"),
5867                         P_("Vertical scale center"),
5868                         -G_MAXFLOAT, G_MAXFLOAT,
5869                         0.0,
5870                         CLUTTER_PARAM_READWRITE);
5871
5872   /**
5873    * ClutterActor:scale-gravity:
5874    *
5875    * The center point for scaling expressed as a #ClutterGravity
5876    *
5877    * Since: 1.0
5878    */
5879   obj_props[PROP_SCALE_GRAVITY] =
5880     g_param_spec_enum ("scale-gravity",
5881                        P_("Scale Gravity"),
5882                        P_("The center of scaling"),
5883                        CLUTTER_TYPE_GRAVITY,
5884                        CLUTTER_GRAVITY_NONE,
5885                        CLUTTER_PARAM_READWRITE);
5886
5887   /**
5888    * ClutterActor:rotation-angle-x:
5889    *
5890    * The rotation angle on the X axis.
5891    *
5892    * The #ClutterActor:rotation-angle-x property is animatable.
5893    *
5894    * Since: 0.6
5895    */
5896   obj_props[PROP_ROTATION_ANGLE_X] =
5897     g_param_spec_double ("rotation-angle-x",
5898                          P_("Rotation Angle X"),
5899                          P_("The rotation angle on the X axis"),
5900                          -G_MAXDOUBLE, G_MAXDOUBLE,
5901                          0.0,
5902                          G_PARAM_READWRITE |
5903                          G_PARAM_STATIC_STRINGS |
5904                          CLUTTER_PARAM_ANIMATABLE);
5905
5906   /**
5907    * ClutterActor:rotation-angle-y:
5908    *
5909    * The rotation angle on the Y axis
5910    *
5911    * The #ClutterActor:rotation-angle-y property is animatable.
5912    *
5913    * Since: 0.6
5914    */
5915   obj_props[PROP_ROTATION_ANGLE_Y] =
5916     g_param_spec_double ("rotation-angle-y",
5917                          P_("Rotation Angle Y"),
5918                          P_("The rotation angle on the Y axis"),
5919                          -G_MAXDOUBLE, G_MAXDOUBLE,
5920                          0.0,
5921                          G_PARAM_READWRITE |
5922                          G_PARAM_STATIC_STRINGS |
5923                          CLUTTER_PARAM_ANIMATABLE);
5924
5925   /**
5926    * ClutterActor:rotation-angle-z:
5927    *
5928    * The rotation angle on the Z axis
5929    *
5930    * The #ClutterActor:rotation-angle-z property is animatable.
5931    *
5932    * Since: 0.6
5933    */
5934   obj_props[PROP_ROTATION_ANGLE_Z] =
5935     g_param_spec_double ("rotation-angle-z",
5936                          P_("Rotation Angle Z"),
5937                          P_("The rotation angle on the Z axis"),
5938                          -G_MAXDOUBLE, G_MAXDOUBLE,
5939                          0.0,
5940                          G_PARAM_READWRITE |
5941                          G_PARAM_STATIC_STRINGS |
5942                          CLUTTER_PARAM_ANIMATABLE);
5943
5944   /**
5945    * ClutterActor:rotation-center-x:
5946    *
5947    * The rotation center on the X axis.
5948    *
5949    * Since: 0.6
5950    */
5951   obj_props[PROP_ROTATION_CENTER_X] =
5952     g_param_spec_boxed ("rotation-center-x",
5953                         P_("Rotation Center X"),
5954                         P_("The rotation center on the X axis"),
5955                         CLUTTER_TYPE_VERTEX,
5956                         CLUTTER_PARAM_READWRITE);
5957
5958   /**
5959    * ClutterActor:rotation-center-y:
5960    *
5961    * The rotation center on the Y axis.
5962    *
5963    * Since: 0.6
5964    */
5965   obj_props[PROP_ROTATION_CENTER_Y] =
5966     g_param_spec_boxed ("rotation-center-y",
5967                         P_("Rotation Center Y"),
5968                         P_("The rotation center on the Y axis"),
5969                         CLUTTER_TYPE_VERTEX,
5970                         CLUTTER_PARAM_READWRITE);
5971
5972   /**
5973    * ClutterActor:rotation-center-z:
5974    *
5975    * The rotation center on the Z axis.
5976    *
5977    * Since: 0.6
5978    */
5979   obj_props[PROP_ROTATION_CENTER_Z] =
5980     g_param_spec_boxed ("rotation-center-z",
5981                         P_("Rotation Center Z"),
5982                         P_("The rotation center on the Z axis"),
5983                         CLUTTER_TYPE_VERTEX,
5984                         CLUTTER_PARAM_READWRITE);
5985
5986   /**
5987    * ClutterActor:rotation-center-z-gravity:
5988    *
5989    * The rotation center on the Z axis expressed as a #ClutterGravity.
5990    *
5991    * Since: 1.0
5992    */
5993   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5994     g_param_spec_enum ("rotation-center-z-gravity",
5995                        P_("Rotation Center Z Gravity"),
5996                        P_("Center point for rotation around the Z axis"),
5997                        CLUTTER_TYPE_GRAVITY,
5998                        CLUTTER_GRAVITY_NONE,
5999                        CLUTTER_PARAM_READWRITE);
6000
6001   /**
6002    * ClutterActor:anchor-x:
6003    *
6004    * The X coordinate of an actor's anchor point, relative to
6005    * the actor coordinate space, in pixels
6006    *
6007    * Since: 0.8
6008    */
6009   obj_props[PROP_ANCHOR_X] =
6010     g_param_spec_float ("anchor-x",
6011                         P_("Anchor X"),
6012                         P_("X coordinate of the anchor point"),
6013                         -G_MAXFLOAT, G_MAXFLOAT,
6014                         0,
6015                         CLUTTER_PARAM_READWRITE);
6016
6017   /**
6018    * ClutterActor:anchor-y:
6019    *
6020    * The Y coordinate of an actor's anchor point, relative to
6021    * the actor coordinate space, in pixels
6022    *
6023    * Since: 0.8
6024    */
6025   obj_props[PROP_ANCHOR_Y] =
6026     g_param_spec_float ("anchor-y",
6027                         P_("Anchor Y"),
6028                         P_("Y coordinate of the anchor point"),
6029                         -G_MAXFLOAT, G_MAXFLOAT,
6030                         0,
6031                         CLUTTER_PARAM_READWRITE);
6032
6033   /**
6034    * ClutterActor:anchor-gravity:
6035    *
6036    * The anchor point expressed as a #ClutterGravity
6037    *
6038    * Since: 1.0
6039    */
6040   obj_props[PROP_ANCHOR_GRAVITY] =
6041     g_param_spec_enum ("anchor-gravity",
6042                        P_("Anchor Gravity"),
6043                        P_("The anchor point as a ClutterGravity"),
6044                        CLUTTER_TYPE_GRAVITY,
6045                        CLUTTER_GRAVITY_NONE,
6046                        CLUTTER_PARAM_READWRITE);
6047
6048   /**
6049    * ClutterActor:show-on-set-parent:
6050    *
6051    * If %TRUE, the actor is automatically shown when parented.
6052    *
6053    * Calling clutter_actor_hide() on an actor which has not been
6054    * parented will set this property to %FALSE as a side effect.
6055    *
6056    * Since: 0.8
6057    */
6058   obj_props[PROP_SHOW_ON_SET_PARENT] =
6059     g_param_spec_boolean ("show-on-set-parent",
6060                           P_("Show on set parent"),
6061                           P_("Whether the actor is shown when parented"),
6062                           TRUE,
6063                           CLUTTER_PARAM_READWRITE);
6064
6065   /**
6066    * ClutterActor:clip-to-allocation:
6067    *
6068    * Whether the clip region should track the allocated area
6069    * of the actor.
6070    *
6071    * This property is ignored if a clip area has been explicitly
6072    * set using clutter_actor_set_clip().
6073    *
6074    * Since: 1.0
6075    */
6076   obj_props[PROP_CLIP_TO_ALLOCATION] =
6077     g_param_spec_boolean ("clip-to-allocation",
6078                           P_("Clip to Allocation"),
6079                           P_("Sets the clip region to track the actor's allocation"),
6080                           FALSE,
6081                           CLUTTER_PARAM_READWRITE);
6082
6083   /**
6084    * ClutterActor:text-direction:
6085    *
6086    * The direction of the text inside a #ClutterActor.
6087    *
6088    * Since: 1.0
6089    */
6090   obj_props[PROP_TEXT_DIRECTION] =
6091     g_param_spec_enum ("text-direction",
6092                        P_("Text Direction"),
6093                        P_("Direction of the text"),
6094                        CLUTTER_TYPE_TEXT_DIRECTION,
6095                        CLUTTER_TEXT_DIRECTION_LTR,
6096                        CLUTTER_PARAM_READWRITE);
6097
6098   /**
6099    * ClutterActor:has-pointer:
6100    *
6101    * Whether the actor contains the pointer of a #ClutterInputDevice
6102    * or not.
6103    *
6104    * Since: 1.2
6105    */
6106   obj_props[PROP_HAS_POINTER] =
6107     g_param_spec_boolean ("has-pointer",
6108                           P_("Has Pointer"),
6109                           P_("Whether the actor contains the pointer of an input device"),
6110                           FALSE,
6111                           CLUTTER_PARAM_READABLE);
6112
6113   /**
6114    * ClutterActor:actions:
6115    *
6116    * Adds a #ClutterAction to the actor
6117    *
6118    * Since: 1.4
6119    */
6120   obj_props[PROP_ACTIONS] =
6121     g_param_spec_object ("actions",
6122                          P_("Actions"),
6123                          P_("Adds an action to the actor"),
6124                          CLUTTER_TYPE_ACTION,
6125                          CLUTTER_PARAM_WRITABLE);
6126
6127   /**
6128    * ClutterActor:constraints:
6129    *
6130    * Adds a #ClutterConstraint to the actor
6131    *
6132    * Since: 1.4
6133    */
6134   obj_props[PROP_CONSTRAINTS] =
6135     g_param_spec_object ("constraints",
6136                          P_("Constraints"),
6137                          P_("Adds a constraint to the actor"),
6138                          CLUTTER_TYPE_CONSTRAINT,
6139                          CLUTTER_PARAM_WRITABLE);
6140
6141   /**
6142    * ClutterActor:effect:
6143    *
6144    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6145    *
6146    * Since: 1.4
6147    */
6148   obj_props[PROP_EFFECT] =
6149     g_param_spec_object ("effect",
6150                          P_("Effect"),
6151                          P_("Add an effect to be applied on the actor"),
6152                          CLUTTER_TYPE_EFFECT,
6153                          CLUTTER_PARAM_WRITABLE);
6154
6155   /**
6156    * ClutterActor:layout-manager:
6157    *
6158    * A delegate object for controlling the layout of the children of
6159    * an actor.
6160    *
6161    * Since: 1.10
6162    */
6163   obj_props[PROP_LAYOUT_MANAGER] =
6164     g_param_spec_object ("layout-manager",
6165                          P_("Layout Manager"),
6166                          P_("The object controlling the layout of an actor's children"),
6167                          CLUTTER_TYPE_LAYOUT_MANAGER,
6168                          CLUTTER_PARAM_READWRITE);
6169
6170
6171   /**
6172    * ClutterActor:x-align:
6173    *
6174    * The alignment of an actor on the X axis, if the actor has been given
6175    * extra space for its allocation.
6176    *
6177    * Since: 1.10
6178    */
6179   obj_props[PROP_X_ALIGN] =
6180     g_param_spec_enum ("x-align",
6181                        P_("X Alignment"),
6182                        P_("The alignment of the actor on the X axis within its allocation"),
6183                        CLUTTER_TYPE_ACTOR_ALIGN,
6184                        CLUTTER_ACTOR_ALIGN_FILL,
6185                        CLUTTER_PARAM_READWRITE);
6186
6187   /**
6188    * ClutterActor:y-align:
6189    *
6190    * The alignment of an actor on the Y axis, if the actor has been given
6191    * extra space for its allocation.
6192    *
6193    * Since: 1.10
6194    */
6195   obj_props[PROP_Y_ALIGN] =
6196     g_param_spec_enum ("y-align",
6197                        P_("Y Alignment"),
6198                        P_("The alignment of the actor on the Y axis within its allocation"),
6199                        CLUTTER_TYPE_ACTOR_ALIGN,
6200                        CLUTTER_ACTOR_ALIGN_FILL,
6201                        CLUTTER_PARAM_READWRITE);
6202
6203   /**
6204    * ClutterActor:margin-top:
6205    *
6206    * The margin (in pixels) from the top of the actor.
6207    *
6208    * This property adds a margin to the actor's preferred size; the margin
6209    * will be automatically taken into account when allocating the actor.
6210    *
6211    * Since: 1.10
6212    */
6213   obj_props[PROP_MARGIN_TOP] =
6214     g_param_spec_float ("margin-top",
6215                         P_("Margin Top"),
6216                         P_("Extra space at the top"),
6217                         0.0, G_MAXFLOAT,
6218                         0.0,
6219                         CLUTTER_PARAM_READWRITE);
6220
6221   /**
6222    * ClutterActor:margin-bottom:
6223    *
6224    * The margin (in pixels) from the bottom of the actor.
6225    *
6226    * This property adds a margin to the actor's preferred size; the margin
6227    * will be automatically taken into account when allocating the actor.
6228    *
6229    * Since: 1.10
6230    */
6231   obj_props[PROP_MARGIN_BOTTOM] =
6232     g_param_spec_float ("margin-bottom",
6233                         P_("Margin Bottom"),
6234                         P_("Extra space at the bottom"),
6235                         0.0, G_MAXFLOAT,
6236                         0.0,
6237                         CLUTTER_PARAM_READWRITE);
6238
6239   /**
6240    * ClutterActor:margin-left:
6241    *
6242    * The margin (in pixels) from the left of the actor.
6243    *
6244    * This property adds a margin to the actor's preferred size; the margin
6245    * will be automatically taken into account when allocating the actor.
6246    *
6247    * Since: 1.10
6248    */
6249   obj_props[PROP_MARGIN_LEFT] =
6250     g_param_spec_float ("margin-left",
6251                         P_("Margin Left"),
6252                         P_("Extra space at the left"),
6253                         0.0, G_MAXFLOAT,
6254                         0.0,
6255                         CLUTTER_PARAM_READWRITE);
6256
6257   /**
6258    * ClutterActor:margin-right:
6259    *
6260    * The margin (in pixels) from the right of the actor.
6261    *
6262    * This property adds a margin to the actor's preferred size; the margin
6263    * will be automatically taken into account when allocating the actor.
6264    *
6265    * Since: 1.10
6266    */
6267   obj_props[PROP_MARGIN_RIGHT] =
6268     g_param_spec_float ("margin-right",
6269                         P_("Margin Right"),
6270                         P_("Extra space at the right"),
6271                         0.0, G_MAXFLOAT,
6272                         0.0,
6273                         CLUTTER_PARAM_READWRITE);
6274
6275   /**
6276    * ClutterActor:background-color-set:
6277    *
6278    * Whether the #ClutterActor:background-color property has been set.
6279    *
6280    * Since: 1.10
6281    */
6282   obj_props[PROP_BACKGROUND_COLOR_SET] =
6283     g_param_spec_boolean ("background-color-set",
6284                           P_("Background Color Set"),
6285                           P_("Whether the background color is set"),
6286                           FALSE,
6287                           CLUTTER_PARAM_READABLE);
6288
6289   /**
6290    * ClutterActor:background-color:
6291    *
6292    * Paints a solid fill of the actor's allocation using the specified
6293    * color.
6294    *
6295    * The #ClutterActor:background-color property is animatable.
6296    *
6297    * Since: 1.10
6298    */
6299   obj_props[PROP_BACKGROUND_COLOR] =
6300     clutter_param_spec_color ("background-color",
6301                               P_("Background color"),
6302                               P_("The actor's background color"),
6303                               CLUTTER_COLOR_Transparent,
6304                               G_PARAM_READWRITE |
6305                               G_PARAM_STATIC_STRINGS |
6306                               CLUTTER_PARAM_ANIMATABLE);
6307
6308   /**
6309    * ClutterActor:first-child:
6310    *
6311    * The actor's first child.
6312    *
6313    * Since: 1.10
6314    */
6315   obj_props[PROP_FIRST_CHILD] =
6316     g_param_spec_object ("first-child",
6317                          P_("First Child"),
6318                          P_("The actor's first child"),
6319                          CLUTTER_TYPE_ACTOR,
6320                          CLUTTER_PARAM_READABLE);
6321
6322   /**
6323    * ClutterActor:last-child:
6324    *
6325    * The actor's last child.
6326    *
6327    * Since: 1.10
6328    */
6329   obj_props[PROP_LAST_CHILD] =
6330     g_param_spec_object ("last-child",
6331                          P_("Last Child"),
6332                          P_("The actor's last child"),
6333                          CLUTTER_TYPE_ACTOR,
6334                          CLUTTER_PARAM_READABLE);
6335
6336   /**
6337    * ClutterActor:content:
6338    *
6339    * The #ClutterContent implementation that controls the content
6340    * of the actor.
6341    *
6342    * Since: 1.10
6343    */
6344   obj_props[PROP_CONTENT] =
6345     g_param_spec_object ("content",
6346                          P_("Content"),
6347                          P_("Delegate object for painting the actor's content"),
6348                          CLUTTER_TYPE_CONTENT,
6349                          CLUTTER_PARAM_READWRITE);
6350
6351   /**
6352    * ClutterActor:content-gravity:
6353    *
6354    * The alignment that should be honoured by the #ClutterContent
6355    * set with the #ClutterActor:content property.
6356    *
6357    * Changing the value of this property will change the bounding box of
6358    * the content; you can use the #ClutterActor:content-box property to
6359    * get the position and size of the content within the actor's
6360    * allocation.
6361    *
6362    * This property is meaningful only for #ClutterContent implementations
6363    * that have a preferred size, and if the preferred size is smaller than
6364    * the actor's allocation.
6365    *
6366    * Since: 1.10
6367    */
6368   obj_props[PROP_CONTENT_GRAVITY] =
6369     g_param_spec_enum ("content-gravity",
6370                        P_("Content Gravity"),
6371                        P_("Alignment of the actor's content"),
6372                        CLUTTER_TYPE_CONTENT_GRAVITY,
6373                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6374                        CLUTTER_PARAM_READWRITE);
6375
6376   /**
6377    * ClutterActor:content-box:
6378    *
6379    * The bounding box for the #ClutterContent used by the actor.
6380    *
6381    * The value of this property is controlled by the #ClutterActor:allocation
6382    * and #ClutterActor:content-gravity properties of #ClutterActor.
6383    *
6384    * The bounding box for the content is guaranteed to never exceed the
6385    * allocation's of the actor.
6386    *
6387    * Since: 1.10
6388    */
6389   obj_props[PROP_CONTENT_BOX] =
6390     g_param_spec_boxed ("content-box",
6391                         P_("Content Box"),
6392                         P_("The bounding box of the actor's content"),
6393                         CLUTTER_TYPE_ACTOR_BOX,
6394                         CLUTTER_PARAM_READABLE);
6395
6396   obj_props[PROP_MINIFICATION_FILTER] =
6397     g_param_spec_enum ("minification-filter",
6398                        P_("Minification Filter"),
6399                        P_("The filter used when reducing the size of the content"),
6400                        CLUTTER_TYPE_SCALING_FILTER,
6401                        CLUTTER_SCALING_FILTER_LINEAR,
6402                        CLUTTER_PARAM_READWRITE);
6403
6404   obj_props[PROP_MAGNIFICATION_FILTER] =
6405     g_param_spec_enum ("magnification-filter",
6406                        P_("Magnification Filter"),
6407                        P_("The filter used when increasing the size of the content"),
6408                        CLUTTER_TYPE_SCALING_FILTER,
6409                        CLUTTER_SCALING_FILTER_LINEAR,
6410                        CLUTTER_PARAM_READWRITE);
6411
6412   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6413
6414   /**
6415    * ClutterActor::destroy:
6416    * @actor: the #ClutterActor which emitted the signal
6417    *
6418    * The ::destroy signal notifies that all references held on the
6419    * actor which emitted it should be released.
6420    *
6421    * The ::destroy signal should be used by all holders of a reference
6422    * on @actor.
6423    *
6424    * This signal might result in the finalization of the #ClutterActor
6425    * if all references are released.
6426    *
6427    * Composite actors and actors implementing the #ClutterContainer
6428    * interface should override the default implementation of the
6429    * class handler of this signal and call clutter_actor_destroy() on
6430    * their children. When overriding the default class handler, it is
6431    * required to chain up to the parent's implementation.
6432    *
6433    * Since: 0.2
6434    */
6435   actor_signals[DESTROY] =
6436     g_signal_new (I_("destroy"),
6437                   G_TYPE_FROM_CLASS (object_class),
6438                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6439                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6440                   NULL, NULL,
6441                   _clutter_marshal_VOID__VOID,
6442                   G_TYPE_NONE, 0);
6443   /**
6444    * ClutterActor::show:
6445    * @actor: the object which received the signal
6446    *
6447    * The ::show signal is emitted when an actor is visible and
6448    * rendered on the stage.
6449    *
6450    * Since: 0.2
6451    */
6452   actor_signals[SHOW] =
6453     g_signal_new (I_("show"),
6454                   G_TYPE_FROM_CLASS (object_class),
6455                   G_SIGNAL_RUN_FIRST,
6456                   G_STRUCT_OFFSET (ClutterActorClass, show),
6457                   NULL, NULL,
6458                   _clutter_marshal_VOID__VOID,
6459                   G_TYPE_NONE, 0);
6460   /**
6461    * ClutterActor::hide:
6462    * @actor: the object which received the signal
6463    *
6464    * The ::hide signal is emitted when an actor is no longer rendered
6465    * on the stage.
6466    *
6467    * Since: 0.2
6468    */
6469   actor_signals[HIDE] =
6470     g_signal_new (I_("hide"),
6471                   G_TYPE_FROM_CLASS (object_class),
6472                   G_SIGNAL_RUN_FIRST,
6473                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6474                   NULL, NULL,
6475                   _clutter_marshal_VOID__VOID,
6476                   G_TYPE_NONE, 0);
6477   /**
6478    * ClutterActor::parent-set:
6479    * @actor: the object which received the signal
6480    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6481    *
6482    * This signal is emitted when the parent of the actor changes.
6483    *
6484    * Since: 0.2
6485    */
6486   actor_signals[PARENT_SET] =
6487     g_signal_new (I_("parent-set"),
6488                   G_TYPE_FROM_CLASS (object_class),
6489                   G_SIGNAL_RUN_LAST,
6490                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6491                   NULL, NULL,
6492                   _clutter_marshal_VOID__OBJECT,
6493                   G_TYPE_NONE, 1,
6494                   CLUTTER_TYPE_ACTOR);
6495
6496   /**
6497    * ClutterActor::queue-redraw:
6498    * @actor: the actor we're bubbling the redraw request through
6499    * @origin: the actor which initiated the redraw request
6500    *
6501    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6502    * is called on @origin.
6503    *
6504    * The default implementation for #ClutterActor chains up to the
6505    * parent actor and queues a redraw on the parent, thus "bubbling"
6506    * the redraw queue up through the actor graph. The default
6507    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6508    * in a main loop idle handler.
6509    *
6510    * Note that the @origin actor may be the stage, or a container; it
6511    * does not have to be a leaf node in the actor graph.
6512    *
6513    * Toolkits embedding a #ClutterStage which require a redraw and
6514    * relayout cycle can stop the emission of this signal using the
6515    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6516    * themselves, like:
6517    *
6518    * |[
6519    *   static void
6520    *   on_redraw_complete (gpointer data)
6521    *   {
6522    *     ClutterStage *stage = data;
6523    *
6524    *     /&ast; execute the Clutter drawing pipeline &ast;/
6525    *     clutter_stage_ensure_redraw (stage);
6526    *   }
6527    *
6528    *   static void
6529    *   on_stage_queue_redraw (ClutterStage *stage)
6530    *   {
6531    *     /&ast; this prevents the default handler to run &ast;/
6532    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6533    *
6534    *     /&ast; queue a redraw with the host toolkit and call
6535    *      &ast; a function when the redraw has been completed
6536    *      &ast;/
6537    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6538    *   }
6539    * ]|
6540    *
6541    * <note><para>This signal is emitted before the Clutter paint
6542    * pipeline is executed. If you want to know when the pipeline has
6543    * been completed you should connect to the ::paint signal on the
6544    * Stage with g_signal_connect_after().</para></note>
6545    *
6546    * Since: 1.0
6547    */
6548   actor_signals[QUEUE_REDRAW] =
6549     g_signal_new (I_("queue-redraw"),
6550                   G_TYPE_FROM_CLASS (object_class),
6551                   G_SIGNAL_RUN_LAST |
6552                   G_SIGNAL_NO_HOOKS,
6553                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6554                   NULL, NULL,
6555                   _clutter_marshal_VOID__OBJECT,
6556                   G_TYPE_NONE, 1,
6557                   CLUTTER_TYPE_ACTOR);
6558
6559   /**
6560    * ClutterActor::queue-relayout
6561    * @actor: the actor being queued for relayout
6562    *
6563    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6564    * is called on an actor.
6565    *
6566    * The default implementation for #ClutterActor chains up to the
6567    * parent actor and queues a relayout on the parent, thus "bubbling"
6568    * the relayout queue up through the actor graph.
6569    *
6570    * The main purpose of this signal is to allow relayout to be propagated
6571    * properly in the procense of #ClutterClone actors. Applications will
6572    * not normally need to connect to this signal.
6573    *
6574    * Since: 1.2
6575    */
6576   actor_signals[QUEUE_RELAYOUT] =
6577     g_signal_new (I_("queue-relayout"),
6578                   G_TYPE_FROM_CLASS (object_class),
6579                   G_SIGNAL_RUN_LAST |
6580                   G_SIGNAL_NO_HOOKS,
6581                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6582                   NULL, NULL,
6583                   _clutter_marshal_VOID__VOID,
6584                   G_TYPE_NONE, 0);
6585
6586   /**
6587    * ClutterActor::event:
6588    * @actor: the actor which received the event
6589    * @event: a #ClutterEvent
6590    *
6591    * The ::event signal is emitted each time an event is received
6592    * by the @actor. This signal will be emitted on every actor,
6593    * following the hierarchy chain, until it reaches the top-level
6594    * container (the #ClutterStage).
6595    *
6596    * Return value: %TRUE if the event has been handled by the actor,
6597    *   or %FALSE to continue the emission.
6598    *
6599    * Since: 0.6
6600    */
6601   actor_signals[EVENT] =
6602     g_signal_new (I_("event"),
6603                   G_TYPE_FROM_CLASS (object_class),
6604                   G_SIGNAL_RUN_LAST,
6605                   G_STRUCT_OFFSET (ClutterActorClass, event),
6606                   _clutter_boolean_handled_accumulator, NULL,
6607                   _clutter_marshal_BOOLEAN__BOXED,
6608                   G_TYPE_BOOLEAN, 1,
6609                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6610   /**
6611    * ClutterActor::button-press-event:
6612    * @actor: the actor which received the event
6613    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6614    *
6615    * The ::button-press-event signal is emitted each time a mouse button
6616    * is pressed on @actor.
6617    *
6618    * Return value: %TRUE if the event has been handled by the actor,
6619    *   or %FALSE to continue the emission.
6620    *
6621    * Since: 0.6
6622    */
6623   actor_signals[BUTTON_PRESS_EVENT] =
6624     g_signal_new (I_("button-press-event"),
6625                   G_TYPE_FROM_CLASS (object_class),
6626                   G_SIGNAL_RUN_LAST,
6627                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6628                   _clutter_boolean_handled_accumulator, NULL,
6629                   _clutter_marshal_BOOLEAN__BOXED,
6630                   G_TYPE_BOOLEAN, 1,
6631                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6632   /**
6633    * ClutterActor::button-release-event:
6634    * @actor: the actor which received the event
6635    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6636    *
6637    * The ::button-release-event signal is emitted each time a mouse button
6638    * is released on @actor.
6639    *
6640    * Return value: %TRUE if the event has been handled by the actor,
6641    *   or %FALSE to continue the emission.
6642    *
6643    * Since: 0.6
6644    */
6645   actor_signals[BUTTON_RELEASE_EVENT] =
6646     g_signal_new (I_("button-release-event"),
6647                   G_TYPE_FROM_CLASS (object_class),
6648                   G_SIGNAL_RUN_LAST,
6649                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6650                   _clutter_boolean_handled_accumulator, NULL,
6651                   _clutter_marshal_BOOLEAN__BOXED,
6652                   G_TYPE_BOOLEAN, 1,
6653                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6654   /**
6655    * ClutterActor::scroll-event:
6656    * @actor: the actor which received the event
6657    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6658    *
6659    * The ::scroll-event signal is emitted each time the mouse is
6660    * scrolled on @actor
6661    *
6662    * Return value: %TRUE if the event has been handled by the actor,
6663    *   or %FALSE to continue the emission.
6664    *
6665    * Since: 0.6
6666    */
6667   actor_signals[SCROLL_EVENT] =
6668     g_signal_new (I_("scroll-event"),
6669                   G_TYPE_FROM_CLASS (object_class),
6670                   G_SIGNAL_RUN_LAST,
6671                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6672                   _clutter_boolean_handled_accumulator, NULL,
6673                   _clutter_marshal_BOOLEAN__BOXED,
6674                   G_TYPE_BOOLEAN, 1,
6675                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6676   /**
6677    * ClutterActor::key-press-event:
6678    * @actor: the actor which received the event
6679    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6680    *
6681    * The ::key-press-event signal is emitted each time a keyboard button
6682    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6683    *
6684    * Return value: %TRUE if the event has been handled by the actor,
6685    *   or %FALSE to continue the emission.
6686    *
6687    * Since: 0.6
6688    */
6689   actor_signals[KEY_PRESS_EVENT] =
6690     g_signal_new (I_("key-press-event"),
6691                   G_TYPE_FROM_CLASS (object_class),
6692                   G_SIGNAL_RUN_LAST,
6693                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6694                   _clutter_boolean_handled_accumulator, NULL,
6695                   _clutter_marshal_BOOLEAN__BOXED,
6696                   G_TYPE_BOOLEAN, 1,
6697                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6698   /**
6699    * ClutterActor::key-release-event:
6700    * @actor: the actor which received the event
6701    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6702    *
6703    * The ::key-release-event signal is emitted each time a keyboard button
6704    * is released while @actor has key focus (see
6705    * clutter_stage_set_key_focus()).
6706    *
6707    * Return value: %TRUE if the event has been handled by the actor,
6708    *   or %FALSE to continue the emission.
6709    *
6710    * Since: 0.6
6711    */
6712   actor_signals[KEY_RELEASE_EVENT] =
6713     g_signal_new (I_("key-release-event"),
6714                   G_TYPE_FROM_CLASS (object_class),
6715                   G_SIGNAL_RUN_LAST,
6716                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6717                   _clutter_boolean_handled_accumulator, NULL,
6718                   _clutter_marshal_BOOLEAN__BOXED,
6719                   G_TYPE_BOOLEAN, 1,
6720                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6721   /**
6722    * ClutterActor::motion-event:
6723    * @actor: the actor which received the event
6724    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6725    *
6726    * The ::motion-event signal is emitted each time the mouse pointer is
6727    * moved over @actor.
6728    *
6729    * Return value: %TRUE if the event has been handled by the actor,
6730    *   or %FALSE to continue the emission.
6731    *
6732    * Since: 0.6
6733    */
6734   actor_signals[MOTION_EVENT] =
6735     g_signal_new (I_("motion-event"),
6736                   G_TYPE_FROM_CLASS (object_class),
6737                   G_SIGNAL_RUN_LAST,
6738                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6739                   _clutter_boolean_handled_accumulator, NULL,
6740                   _clutter_marshal_BOOLEAN__BOXED,
6741                   G_TYPE_BOOLEAN, 1,
6742                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6743
6744   /**
6745    * ClutterActor::key-focus-in:
6746    * @actor: the actor which now has key focus
6747    *
6748    * The ::key-focus-in signal is emitted when @actor receives key focus.
6749    *
6750    * Since: 0.6
6751    */
6752   actor_signals[KEY_FOCUS_IN] =
6753     g_signal_new (I_("key-focus-in"),
6754                   G_TYPE_FROM_CLASS (object_class),
6755                   G_SIGNAL_RUN_LAST,
6756                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6757                   NULL, NULL,
6758                   _clutter_marshal_VOID__VOID,
6759                   G_TYPE_NONE, 0);
6760
6761   /**
6762    * ClutterActor::key-focus-out:
6763    * @actor: the actor which now has key focus
6764    *
6765    * The ::key-focus-out signal is emitted when @actor loses key focus.
6766    *
6767    * Since: 0.6
6768    */
6769   actor_signals[KEY_FOCUS_OUT] =
6770     g_signal_new (I_("key-focus-out"),
6771                   G_TYPE_FROM_CLASS (object_class),
6772                   G_SIGNAL_RUN_LAST,
6773                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6774                   NULL, NULL,
6775                   _clutter_marshal_VOID__VOID,
6776                   G_TYPE_NONE, 0);
6777
6778   /**
6779    * ClutterActor::enter-event:
6780    * @actor: the actor which the pointer has entered.
6781    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6782    *
6783    * The ::enter-event signal is emitted when the pointer enters the @actor
6784    *
6785    * Return value: %TRUE if the event has been handled by the actor,
6786    *   or %FALSE to continue the emission.
6787    *
6788    * Since: 0.6
6789    */
6790   actor_signals[ENTER_EVENT] =
6791     g_signal_new (I_("enter-event"),
6792                   G_TYPE_FROM_CLASS (object_class),
6793                   G_SIGNAL_RUN_LAST,
6794                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6795                   _clutter_boolean_handled_accumulator, NULL,
6796                   _clutter_marshal_BOOLEAN__BOXED,
6797                   G_TYPE_BOOLEAN, 1,
6798                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6799
6800   /**
6801    * ClutterActor::leave-event:
6802    * @actor: the actor which the pointer has left
6803    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6804    *
6805    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6806    *
6807    * Return value: %TRUE if the event has been handled by the actor,
6808    *   or %FALSE to continue the emission.
6809    *
6810    * Since: 0.6
6811    */
6812   actor_signals[LEAVE_EVENT] =
6813     g_signal_new (I_("leave-event"),
6814                   G_TYPE_FROM_CLASS (object_class),
6815                   G_SIGNAL_RUN_LAST,
6816                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6817                   _clutter_boolean_handled_accumulator, NULL,
6818                   _clutter_marshal_BOOLEAN__BOXED,
6819                   G_TYPE_BOOLEAN, 1,
6820                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6821
6822   /**
6823    * ClutterActor::captured-event:
6824    * @actor: the actor which received the signal
6825    * @event: a #ClutterEvent
6826    *
6827    * The ::captured-event signal is emitted when an event is captured
6828    * by Clutter. This signal will be emitted starting from the top-level
6829    * container (the #ClutterStage) to the actor which received the event
6830    * going down the hierarchy. This signal can be used to intercept every
6831    * event before the specialized events (like
6832    * ClutterActor::button-press-event or ::key-released-event) are
6833    * emitted.
6834    *
6835    * Return value: %TRUE if the event has been handled by the actor,
6836    *   or %FALSE to continue the emission.
6837    *
6838    * Since: 0.6
6839    */
6840   actor_signals[CAPTURED_EVENT] =
6841     g_signal_new (I_("captured-event"),
6842                   G_TYPE_FROM_CLASS (object_class),
6843                   G_SIGNAL_RUN_LAST,
6844                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6845                   _clutter_boolean_handled_accumulator, NULL,
6846                   _clutter_marshal_BOOLEAN__BOXED,
6847                   G_TYPE_BOOLEAN, 1,
6848                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6849
6850   /**
6851    * ClutterActor::paint:
6852    * @actor: the #ClutterActor that received the signal
6853    *
6854    * The ::paint signal is emitted each time an actor is being painted.
6855    *
6856    * Subclasses of #ClutterActor should override the class signal handler
6857    * and paint themselves in that function.
6858    *
6859    * It is possible to connect a handler to the ::paint signal in order
6860    * to set up some custom aspect of a paint.
6861    *
6862    * Since: 0.8
6863    */
6864   actor_signals[PAINT] =
6865     g_signal_new (I_("paint"),
6866                   G_TYPE_FROM_CLASS (object_class),
6867                   G_SIGNAL_RUN_LAST |
6868                   G_SIGNAL_NO_HOOKS,
6869                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6870                   NULL, NULL,
6871                   _clutter_marshal_VOID__VOID,
6872                   G_TYPE_NONE, 0);
6873   /**
6874    * ClutterActor::realize:
6875    * @actor: the #ClutterActor that received the signal
6876    *
6877    * The ::realize signal is emitted each time an actor is being
6878    * realized.
6879    *
6880    * Since: 0.8
6881    */
6882   actor_signals[REALIZE] =
6883     g_signal_new (I_("realize"),
6884                   G_TYPE_FROM_CLASS (object_class),
6885                   G_SIGNAL_RUN_LAST,
6886                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6887                   NULL, NULL,
6888                   _clutter_marshal_VOID__VOID,
6889                   G_TYPE_NONE, 0);
6890   /**
6891    * ClutterActor::unrealize:
6892    * @actor: the #ClutterActor that received the signal
6893    *
6894    * The ::unrealize signal is emitted each time an actor is being
6895    * unrealized.
6896    *
6897    * Since: 0.8
6898    */
6899   actor_signals[UNREALIZE] =
6900     g_signal_new (I_("unrealize"),
6901                   G_TYPE_FROM_CLASS (object_class),
6902                   G_SIGNAL_RUN_LAST,
6903                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6904                   NULL, NULL,
6905                   _clutter_marshal_VOID__VOID,
6906                   G_TYPE_NONE, 0);
6907
6908   /**
6909    * ClutterActor::pick:
6910    * @actor: the #ClutterActor that received the signal
6911    * @color: the #ClutterColor to be used when picking
6912    *
6913    * The ::pick signal is emitted each time an actor is being painted
6914    * in "pick mode". The pick mode is used to identify the actor during
6915    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6916    * The actor should paint its shape using the passed @pick_color.
6917    *
6918    * Subclasses of #ClutterActor should override the class signal handler
6919    * and paint themselves in that function.
6920    *
6921    * It is possible to connect a handler to the ::pick signal in order
6922    * to set up some custom aspect of a paint in pick mode.
6923    *
6924    * Since: 1.0
6925    */
6926   actor_signals[PICK] =
6927     g_signal_new (I_("pick"),
6928                   G_TYPE_FROM_CLASS (object_class),
6929                   G_SIGNAL_RUN_LAST,
6930                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6931                   NULL, NULL,
6932                   _clutter_marshal_VOID__BOXED,
6933                   G_TYPE_NONE, 1,
6934                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6935
6936   /**
6937    * ClutterActor::allocation-changed:
6938    * @actor: the #ClutterActor that emitted the signal
6939    * @box: a #ClutterActorBox with the new allocation
6940    * @flags: #ClutterAllocationFlags for the allocation
6941    *
6942    * The ::allocation-changed signal is emitted when the
6943    * #ClutterActor:allocation property changes. Usually, application
6944    * code should just use the notifications for the :allocation property
6945    * but if you want to track the allocation flags as well, for instance
6946    * to know whether the absolute origin of @actor changed, then you might
6947    * want use this signal instead.
6948    *
6949    * Since: 1.0
6950    */
6951   actor_signals[ALLOCATION_CHANGED] =
6952     g_signal_new (I_("allocation-changed"),
6953                   G_TYPE_FROM_CLASS (object_class),
6954                   G_SIGNAL_RUN_LAST,
6955                   0,
6956                   NULL, NULL,
6957                   _clutter_marshal_VOID__BOXED_FLAGS,
6958                   G_TYPE_NONE, 2,
6959                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6960                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6961 }
6962
6963 static void
6964 clutter_actor_init (ClutterActor *self)
6965 {
6966   ClutterActorPrivate *priv;
6967
6968   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6969
6970   priv->id = _clutter_context_acquire_id (self);
6971   priv->pick_id = -1;
6972
6973   priv->opacity = 0xff;
6974   priv->show_on_set_parent = TRUE;
6975
6976   priv->needs_width_request = TRUE;
6977   priv->needs_height_request = TRUE;
6978   priv->needs_allocation = TRUE;
6979
6980   priv->cached_width_age = 1;
6981   priv->cached_height_age = 1;
6982
6983   priv->opacity_override = -1;
6984   priv->enable_model_view_transform = TRUE;
6985
6986   /* Initialize an empty paint volume to start with */
6987   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6988   priv->last_paint_volume_valid = TRUE;
6989
6990   priv->transform_valid = FALSE;
6991
6992   /* the default is to stretch the content, to match the
6993    * current behaviour of basically all actors. also, it's
6994    * the easiest thing to compute.
6995    */
6996   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6997   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6998   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6999 }
7000
7001 /**
7002  * clutter_actor_new:
7003  *
7004  * Creates a new #ClutterActor.
7005  *
7006  * A newly created actor has a floating reference, which will be sunk
7007  * when it is added to another actor.
7008  *
7009  * Return value: (transfer full): the newly created #ClutterActor
7010  *
7011  * Since: 1.10
7012  */
7013 ClutterActor *
7014 clutter_actor_new (void)
7015 {
7016   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7017 }
7018
7019 /**
7020  * clutter_actor_destroy:
7021  * @self: a #ClutterActor
7022  *
7023  * Destroys an actor.  When an actor is destroyed, it will break any
7024  * references it holds to other objects.  If the actor is inside a
7025  * container, the actor will be removed.
7026  *
7027  * When you destroy a container, its children will be destroyed as well.
7028  *
7029  * Note: you cannot destroy the #ClutterStage returned by
7030  * clutter_stage_get_default().
7031  */
7032 void
7033 clutter_actor_destroy (ClutterActor *self)
7034 {
7035   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7036
7037   g_object_ref (self);
7038
7039   /* avoid recursion while destroying */
7040   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7041     {
7042       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7043
7044       g_object_run_dispose (G_OBJECT (self));
7045
7046       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7047     }
7048
7049   g_object_unref (self);
7050 }
7051
7052 void
7053 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7054                                     ClutterPaintVolume *clip)
7055 {
7056   ClutterActorPrivate *priv = self->priv;
7057   ClutterPaintVolume *pv;
7058   gboolean clipped;
7059
7060   /* Remove queue entry early in the process, otherwise a new
7061      queue_redraw() during signal handling could put back this
7062      object in the stage redraw list (but the entry is freed as
7063      soon as we return from this function, causing a segfault
7064      later)
7065   */
7066   priv->queue_redraw_entry = NULL;
7067
7068   /* If we've been explicitly passed a clip volume then there's
7069    * nothing more to calculate, but otherwise the only thing we know
7070    * is that the change is constrained to the given actor.
7071    *
7072    * The idea is that if we know the paint volume for where the actor
7073    * was last drawn (in eye coordinates) and we also have the paint
7074    * volume for where it will be drawn next (in actor coordinates)
7075    * then if we queue a redraw for both these volumes that will cover
7076    * everything that needs to be redrawn to clear the old view and
7077    * show the latest view of the actor.
7078    *
7079    * Don't clip this redraw if we don't know what position we had for
7080    * the previous redraw since we don't know where to set the clip so
7081    * it will clear the actor as it is currently.
7082    */
7083   if (clip)
7084     {
7085       _clutter_actor_set_queue_redraw_clip (self, clip);
7086       clipped = TRUE;
7087     }
7088   else if (G_LIKELY (priv->last_paint_volume_valid))
7089     {
7090       pv = _clutter_actor_get_paint_volume_mutable (self);
7091       if (pv)
7092         {
7093           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7094
7095           /* make sure we redraw the actors old position... */
7096           _clutter_actor_set_queue_redraw_clip (stage,
7097                                                 &priv->last_paint_volume);
7098           _clutter_actor_signal_queue_redraw (stage, stage);
7099           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7100
7101           /* XXX: Ideally the redraw signal would take a clip volume
7102            * argument, but that would be an ABI break. Until we can
7103            * break the ABI we pass the argument out-of-band
7104            */
7105
7106           /* setup the clip for the actors new position... */
7107           _clutter_actor_set_queue_redraw_clip (self, pv);
7108           clipped = TRUE;
7109         }
7110       else
7111         clipped = FALSE;
7112     }
7113   else
7114     clipped = FALSE;
7115
7116   _clutter_actor_signal_queue_redraw (self, self);
7117
7118   /* Just in case anyone is manually firing redraw signals without
7119    * using the public queue_redraw() API we are careful to ensure that
7120    * our out-of-band clip member is cleared before returning...
7121    *
7122    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7123    */
7124   if (G_LIKELY (clipped))
7125     _clutter_actor_set_queue_redraw_clip (self, NULL);
7126 }
7127
7128 static void
7129 _clutter_actor_get_allocation_clip (ClutterActor *self,
7130                                     ClutterActorBox *clip)
7131 {
7132   ClutterActorBox allocation;
7133
7134   /* XXX: we don't care if we get an out of date allocation here
7135    * because clutter_actor_queue_redraw_with_clip knows to ignore
7136    * the clip if the actor's allocation is invalid.
7137    *
7138    * This is noted because clutter_actor_get_allocation_box does some
7139    * unnecessary work to support buggy code with a comment suggesting
7140    * that it could be changed later which would be good for this use
7141    * case!
7142    */
7143   clutter_actor_get_allocation_box (self, &allocation);
7144
7145   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7146    * actor's own coordinate space but the allocation is in parent
7147    * coordinates */
7148   clip->x1 = 0;
7149   clip->y1 = 0;
7150   clip->x2 = allocation.x2 - allocation.x1;
7151   clip->y2 = allocation.y2 - allocation.y1;
7152 }
7153
7154 void
7155 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7156                                   ClutterRedrawFlags  flags,
7157                                   ClutterPaintVolume *volume,
7158                                   ClutterEffect      *effect)
7159 {
7160   ClutterActorPrivate *priv = self->priv;
7161   ClutterPaintVolume allocation_pv;
7162   ClutterPaintVolume *pv;
7163   gboolean should_free_pv;
7164   ClutterActor *stage;
7165
7166   /* Here's an outline of the actor queue redraw mechanism:
7167    *
7168    * The process starts in one of the following two functions which
7169    * are wrappers for this function:
7170    * clutter_actor_queue_redraw
7171    * _clutter_actor_queue_redraw_with_clip
7172    *
7173    * additionally, an effect can queue a redraw by wrapping this
7174    * function in clutter_effect_queue_rerun
7175    *
7176    * This functions queues an entry in a list associated with the
7177    * stage which is a list of actors that queued a redraw while
7178    * updating the timelines, performing layouting and processing other
7179    * mainloop sources before the next paint starts.
7180    *
7181    * We aim to minimize the processing done at this point because
7182    * there is a good chance other events will happen while updating
7183    * the scenegraph that would invalidate any expensive work we might
7184    * otherwise try to do here. For example we don't try and resolve
7185    * the screen space bounding box of an actor at this stage so as to
7186    * minimize how much of the screen redraw because it's possible
7187    * something else will happen which will force a full redraw anyway.
7188    *
7189    * When all updates are complete and we come to paint the stage then
7190    * we iterate this list and actually emit the "queue-redraw" signals
7191    * for each of the listed actors which will bubble up to the stage
7192    * for each actor and at that point we will transform the actors
7193    * paint volume into screen coordinates to determine the clip region
7194    * for what needs to be redrawn in the next paint.
7195    *
7196    * Besides minimizing redundant work another reason for this
7197    * deferred design is that it's more likely we will be able to
7198    * determine the paint volume of an actor once we've finished
7199    * updating the scenegraph because its allocation should be up to
7200    * date. NB: If we can't determine an actors paint volume then we
7201    * can't automatically queue a clipped redraw which can make a big
7202    * difference to performance.
7203    *
7204    * So the control flow goes like this:
7205    * One of clutter_actor_queue_redraw,
7206    *        _clutter_actor_queue_redraw_with_clip
7207    *     or clutter_effect_queue_rerun
7208    *
7209    * then control moves to:
7210    *   _clutter_stage_queue_actor_redraw
7211    *
7212    * later during _clutter_stage_do_update, once relayouting is done
7213    * and the scenegraph has been updated we will call:
7214    * _clutter_stage_finish_queue_redraws
7215    *
7216    * _clutter_stage_finish_queue_redraws will call
7217    * _clutter_actor_finish_queue_redraw for each listed actor.
7218    * Note: actors *are* allowed to queue further redraws during this
7219    * process (considering clone actors or texture_new_from_actor which
7220    * respond to their source queueing a redraw by queuing a redraw
7221    * themselves). We repeat the process until the list is empty.
7222    *
7223    * This will result in the "queue-redraw" signal being fired for
7224    * each actor which will pass control to the default signal handler:
7225    * clutter_actor_real_queue_redraw
7226    *
7227    * This will bubble up to the stages handler:
7228    * clutter_stage_real_queue_redraw
7229    *
7230    * clutter_stage_real_queue_redraw will transform the actors paint
7231    * volume into screen space and add it as a clip region for the next
7232    * paint.
7233    */
7234
7235   /* ignore queueing a redraw for actors being destroyed */
7236   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7237     return;
7238
7239   stage = _clutter_actor_get_stage_internal (self);
7240
7241   /* Ignore queueing a redraw for actors not descended from a stage */
7242   if (stage == NULL)
7243     return;
7244
7245   /* ignore queueing a redraw on stages that are being destroyed */
7246   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7247     return;
7248
7249   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7250     {
7251       ClutterActorBox allocation_clip;
7252       ClutterVertex origin;
7253
7254       /* If the actor doesn't have a valid allocation then we will
7255        * queue a full stage redraw. */
7256       if (priv->needs_allocation)
7257         {
7258           /* NB: NULL denotes an undefined clip which will result in a
7259            * full redraw... */
7260           _clutter_actor_set_queue_redraw_clip (self, NULL);
7261           _clutter_actor_signal_queue_redraw (self, self);
7262           return;
7263         }
7264
7265       _clutter_paint_volume_init_static (&allocation_pv, self);
7266       pv = &allocation_pv;
7267
7268       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7269
7270       origin.x = allocation_clip.x1;
7271       origin.y = allocation_clip.y1;
7272       origin.z = 0;
7273       clutter_paint_volume_set_origin (pv, &origin);
7274       clutter_paint_volume_set_width (pv,
7275                                       allocation_clip.x2 - allocation_clip.x1);
7276       clutter_paint_volume_set_height (pv,
7277                                        allocation_clip.y2 -
7278                                        allocation_clip.y1);
7279       should_free_pv = TRUE;
7280     }
7281   else
7282     {
7283       pv = volume;
7284       should_free_pv = FALSE;
7285     }
7286
7287   self->priv->queue_redraw_entry =
7288     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7289                                        priv->queue_redraw_entry,
7290                                        self,
7291                                        pv);
7292
7293   if (should_free_pv)
7294     clutter_paint_volume_free (pv);
7295
7296   /* If this is the first redraw queued then we can directly use the
7297      effect parameter */
7298   if (!priv->is_dirty)
7299     priv->effect_to_redraw = effect;
7300   /* Otherwise we need to merge it with the existing effect parameter */
7301   else if (effect != NULL)
7302     {
7303       /* If there's already an effect then we need to use whichever is
7304          later in the chain of actors. Otherwise a full redraw has
7305          already been queued on the actor so we need to ignore the
7306          effect parameter */
7307       if (priv->effect_to_redraw != NULL)
7308         {
7309           if (priv->effects == NULL)
7310             g_warning ("Redraw queued with an effect that is "
7311                        "not applied to the actor");
7312           else
7313             {
7314               const GList *l;
7315
7316               for (l = _clutter_meta_group_peek_metas (priv->effects);
7317                    l != NULL;
7318                    l = l->next)
7319                 {
7320                   if (l->data == priv->effect_to_redraw ||
7321                       l->data == effect)
7322                     priv->effect_to_redraw = l->data;
7323                 }
7324             }
7325         }
7326     }
7327   else
7328     {
7329       /* If no effect is specified then we need to redraw the whole
7330          actor */
7331       priv->effect_to_redraw = NULL;
7332     }
7333
7334   priv->is_dirty = TRUE;
7335 }
7336
7337 /**
7338  * clutter_actor_queue_redraw:
7339  * @self: A #ClutterActor
7340  *
7341  * Queues up a redraw of an actor and any children. The redraw occurs
7342  * once the main loop becomes idle (after the current batch of events
7343  * has been processed, roughly).
7344  *
7345  * Applications rarely need to call this, as redraws are handled
7346  * automatically by modification functions.
7347  *
7348  * This function will not do anything if @self is not visible, or
7349  * if the actor is inside an invisible part of the scenegraph.
7350  *
7351  * Also be aware that painting is a NOP for actors with an opacity of
7352  * 0
7353  *
7354  * When you are implementing a custom actor you must queue a redraw
7355  * whenever some private state changes that will affect painting or
7356  * picking of your actor.
7357  */
7358 void
7359 clutter_actor_queue_redraw (ClutterActor *self)
7360 {
7361   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7362
7363   _clutter_actor_queue_redraw_full (self,
7364                                     0, /* flags */
7365                                     NULL, /* clip volume */
7366                                     NULL /* effect */);
7367 }
7368
7369 /*< private >
7370  * _clutter_actor_queue_redraw_with_clip:
7371  * @self: A #ClutterActor
7372  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7373  *   this queue redraw.
7374  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7375  *   redrawn or %NULL if you are just using a @flag to state your
7376  *   desired clipping.
7377  *
7378  * Queues up a clipped redraw of an actor and any children. The redraw
7379  * occurs once the main loop becomes idle (after the current batch of
7380  * events has been processed, roughly).
7381  *
7382  * If no flags are given the clip volume is defined by @volume
7383  * specified in actor coordinates and tells Clutter that only content
7384  * within this volume has been changed so Clutter can optionally
7385  * optimize the redraw.
7386  *
7387  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7388  * should be %NULL and this tells Clutter to use the actor's current
7389  * allocation as a clip box. This flag can only be used for 2D actors,
7390  * because any actor with depth may be projected outside its
7391  * allocation.
7392  *
7393  * Applications rarely need to call this, as redraws are handled
7394  * automatically by modification functions.
7395  *
7396  * This function will not do anything if @self is not visible, or if
7397  * the actor is inside an invisible part of the scenegraph.
7398  *
7399  * Also be aware that painting is a NOP for actors with an opacity of
7400  * 0
7401  *
7402  * When you are implementing a custom actor you must queue a redraw
7403  * whenever some private state changes that will affect painting or
7404  * picking of your actor.
7405  */
7406 void
7407 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7408                                        ClutterRedrawFlags  flags,
7409                                        ClutterPaintVolume *volume)
7410 {
7411   _clutter_actor_queue_redraw_full (self,
7412                                     flags, /* flags */
7413                                     volume, /* clip volume */
7414                                     NULL /* effect */);
7415 }
7416
7417 static void
7418 _clutter_actor_queue_only_relayout (ClutterActor *self)
7419 {
7420   ClutterActorPrivate *priv = self->priv;
7421
7422   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7423     return;
7424
7425   if (priv->needs_width_request &&
7426       priv->needs_height_request &&
7427       priv->needs_allocation)
7428     return; /* save some cpu cycles */
7429
7430 #if CLUTTER_ENABLE_DEBUG
7431   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7432     {
7433       g_warning ("The actor '%s' is currently inside an allocation "
7434                  "cycle; calling clutter_actor_queue_relayout() is "
7435                  "not recommended",
7436                  _clutter_actor_get_debug_name (self));
7437     }
7438 #endif /* CLUTTER_ENABLE_DEBUG */
7439
7440   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7441 }
7442
7443 /**
7444  * clutter_actor_queue_redraw_with_clip:
7445  * @self: a #ClutterActor
7446  * @clip: (allow-none): a rectangular clip region, or %NULL
7447  *
7448  * Queues a redraw on @self limited to a specific, actor-relative
7449  * rectangular area.
7450  *
7451  * If @clip is %NULL this function is equivalent to
7452  * clutter_actor_queue_redraw().
7453  *
7454  * Since: 1.10
7455  */
7456 void
7457 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7458                                       const cairo_rectangle_int_t *clip)
7459 {
7460   ClutterPaintVolume volume;
7461   ClutterVertex origin;
7462
7463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7464
7465   if (clip == NULL)
7466     {
7467       clutter_actor_queue_redraw (self);
7468       return;
7469     }
7470
7471   _clutter_paint_volume_init_static (&volume, self);
7472
7473   origin.x = clip->x;
7474   origin.y = clip->y;
7475   origin.z = 0.0f;
7476
7477   clutter_paint_volume_set_origin (&volume, &origin);
7478   clutter_paint_volume_set_width (&volume, clip->width);
7479   clutter_paint_volume_set_height (&volume, clip->height);
7480
7481   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7482
7483   clutter_paint_volume_free (&volume);
7484 }
7485
7486 /**
7487  * clutter_actor_queue_relayout:
7488  * @self: A #ClutterActor
7489  *
7490  * Indicates that the actor's size request or other layout-affecting
7491  * properties may have changed. This function is used inside #ClutterActor
7492  * subclass implementations, not by applications directly.
7493  *
7494  * Queueing a new layout automatically queues a redraw as well.
7495  *
7496  * Since: 0.8
7497  */
7498 void
7499 clutter_actor_queue_relayout (ClutterActor *self)
7500 {
7501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7502
7503   _clutter_actor_queue_only_relayout (self);
7504   clutter_actor_queue_redraw (self);
7505 }
7506
7507 /**
7508  * clutter_actor_get_preferred_size:
7509  * @self: a #ClutterActor
7510  * @min_width_p: (out) (allow-none): return location for the minimum
7511  *   width, or %NULL
7512  * @min_height_p: (out) (allow-none): return location for the minimum
7513  *   height, or %NULL
7514  * @natural_width_p: (out) (allow-none): return location for the natural
7515  *   width, or %NULL
7516  * @natural_height_p: (out) (allow-none): return location for the natural
7517  *   height, or %NULL
7518  *
7519  * Computes the preferred minimum and natural size of an actor, taking into
7520  * account the actor's geometry management (either height-for-width
7521  * or width-for-height).
7522  *
7523  * The width and height used to compute the preferred height and preferred
7524  * width are the actor's natural ones.
7525  *
7526  * If you need to control the height for the preferred width, or the width for
7527  * the preferred height, you should use clutter_actor_get_preferred_width()
7528  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7529  * geometry management using the #ClutterActor:request-mode property.
7530  *
7531  * Since: 0.8
7532  */
7533 void
7534 clutter_actor_get_preferred_size (ClutterActor *self,
7535                                   gfloat       *min_width_p,
7536                                   gfloat       *min_height_p,
7537                                   gfloat       *natural_width_p,
7538                                   gfloat       *natural_height_p)
7539 {
7540   ClutterActorPrivate *priv;
7541   gfloat min_width, min_height;
7542   gfloat natural_width, natural_height;
7543
7544   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7545
7546   priv = self->priv;
7547
7548   min_width = min_height = 0;
7549   natural_width = natural_height = 0;
7550
7551   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7552     {
7553       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7554       clutter_actor_get_preferred_width (self, -1,
7555                                          &min_width,
7556                                          &natural_width);
7557       clutter_actor_get_preferred_height (self, natural_width,
7558                                           &min_height,
7559                                           &natural_height);
7560     }
7561   else
7562     {
7563       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7564       clutter_actor_get_preferred_height (self, -1,
7565                                           &min_height,
7566                                           &natural_height);
7567       clutter_actor_get_preferred_width (self, natural_height,
7568                                          &min_width,
7569                                          &natural_width);
7570     }
7571
7572   if (min_width_p)
7573     *min_width_p = min_width;
7574
7575   if (min_height_p)
7576     *min_height_p = min_height;
7577
7578   if (natural_width_p)
7579     *natural_width_p = natural_width;
7580
7581   if (natural_height_p)
7582     *natural_height_p = natural_height;
7583 }
7584
7585 /*< private >
7586  * effective_align:
7587  * @align: a #ClutterActorAlign
7588  * @direction: a #ClutterTextDirection
7589  *
7590  * Retrieves the correct alignment depending on the text direction
7591  *
7592  * Return value: the effective alignment
7593  */
7594 static ClutterActorAlign
7595 effective_align (ClutterActorAlign    align,
7596                  ClutterTextDirection direction)
7597 {
7598   ClutterActorAlign res;
7599
7600   switch (align)
7601     {
7602     case CLUTTER_ACTOR_ALIGN_START:
7603       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7604           ? CLUTTER_ACTOR_ALIGN_END
7605           : CLUTTER_ACTOR_ALIGN_START;
7606       break;
7607
7608     case CLUTTER_ACTOR_ALIGN_END:
7609       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7610           ? CLUTTER_ACTOR_ALIGN_START
7611           : CLUTTER_ACTOR_ALIGN_END;
7612       break;
7613
7614     default:
7615       res = align;
7616       break;
7617     }
7618
7619   return res;
7620 }
7621
7622 static inline void
7623 adjust_for_margin (float  margin_start,
7624                    float  margin_end,
7625                    float *minimum_size,
7626                    float *natural_size,
7627                    float *allocated_start,
7628                    float *allocated_end)
7629 {
7630   *minimum_size -= (margin_start + margin_end);
7631   *natural_size -= (margin_start + margin_end);
7632   *allocated_start += margin_start;
7633   *allocated_end -= margin_end;
7634 }
7635
7636 static inline void
7637 adjust_for_alignment (ClutterActorAlign  alignment,
7638                       float              natural_size,
7639                       float             *allocated_start,
7640                       float             *allocated_end)
7641 {
7642   float allocated_size = *allocated_end - *allocated_start;
7643
7644   switch (alignment)
7645     {
7646     case CLUTTER_ACTOR_ALIGN_FILL:
7647       /* do nothing */
7648       break;
7649
7650     case CLUTTER_ACTOR_ALIGN_START:
7651       /* keep start */
7652       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7653       break;
7654
7655     case CLUTTER_ACTOR_ALIGN_END:
7656       if (allocated_size > natural_size)
7657         {
7658           *allocated_start += (allocated_size - natural_size);
7659           *allocated_end = *allocated_start + natural_size;
7660         }
7661       break;
7662
7663     case CLUTTER_ACTOR_ALIGN_CENTER:
7664       if (allocated_size > natural_size)
7665         {
7666           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7667           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7668         }
7669       break;
7670     }
7671 }
7672
7673 /*< private >
7674  * clutter_actor_adjust_width:
7675  * @self: a #ClutterActor
7676  * @minimum_width: (inout): the actor's preferred minimum width, which
7677  *   will be adjusted depending on the margin
7678  * @natural_width: (inout): the actor's preferred natural width, which
7679  *   will be adjusted depending on the margin
7680  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7681  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7682  *
7683  * Adjusts the preferred and allocated position and size of an actor,
7684  * depending on the margin and alignment properties.
7685  */
7686 static void
7687 clutter_actor_adjust_width (ClutterActor *self,
7688                             gfloat       *minimum_width,
7689                             gfloat       *natural_width,
7690                             gfloat       *adjusted_x1,
7691                             gfloat       *adjusted_x2)
7692 {
7693   ClutterTextDirection text_dir;
7694   const ClutterLayoutInfo *info;
7695
7696   info = _clutter_actor_get_layout_info_or_defaults (self);
7697   text_dir = clutter_actor_get_text_direction (self);
7698
7699   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7700
7701   /* this will tweak natural_width to remove the margin, so that
7702    * adjust_for_alignment() will use the correct size
7703    */
7704   adjust_for_margin (info->margin.left, info->margin.right,
7705                      minimum_width, natural_width,
7706                      adjusted_x1, adjusted_x2);
7707
7708   adjust_for_alignment (effective_align (info->x_align, text_dir),
7709                         *natural_width,
7710                         adjusted_x1, adjusted_x2);
7711 }
7712
7713 /*< private >
7714  * clutter_actor_adjust_height:
7715  * @self: a #ClutterActor
7716  * @minimum_height: (inout): the actor's preferred minimum height, which
7717  *   will be adjusted depending on the margin
7718  * @natural_height: (inout): the actor's preferred natural height, which
7719  *   will be adjusted depending on the margin
7720  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7721  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7722  *
7723  * Adjusts the preferred and allocated position and size of an actor,
7724  * depending on the margin and alignment properties.
7725  */
7726 static void
7727 clutter_actor_adjust_height (ClutterActor *self,
7728                              gfloat       *minimum_height,
7729                              gfloat       *natural_height,
7730                              gfloat       *adjusted_y1,
7731                              gfloat       *adjusted_y2)
7732 {
7733   const ClutterLayoutInfo *info;
7734
7735   info = _clutter_actor_get_layout_info_or_defaults (self);
7736
7737   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7738
7739   /* this will tweak natural_height to remove the margin, so that
7740    * adjust_for_alignment() will use the correct size
7741    */
7742   adjust_for_margin (info->margin.top, info->margin.bottom,
7743                      minimum_height, natural_height,
7744                      adjusted_y1,
7745                      adjusted_y2);
7746
7747   /* we don't use effective_align() here, because text direction
7748    * only affects the horizontal axis
7749    */
7750   adjust_for_alignment (info->y_align,
7751                         *natural_height,
7752                         adjusted_y1,
7753                         adjusted_y2);
7754
7755 }
7756
7757 /* looks for a cached size request for this for_size. If not
7758  * found, returns the oldest entry so it can be overwritten */
7759 static gboolean
7760 _clutter_actor_get_cached_size_request (gfloat         for_size,
7761                                         SizeRequest   *cached_size_requests,
7762                                         SizeRequest  **result)
7763 {
7764   guint i;
7765
7766   *result = &cached_size_requests[0];
7767
7768   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7769     {
7770       SizeRequest *sr;
7771
7772       sr = &cached_size_requests[i];
7773
7774       if (sr->age > 0 &&
7775           sr->for_size == for_size)
7776         {
7777           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7778           *result = sr;
7779           return TRUE;
7780         }
7781       else if (sr->age < (*result)->age)
7782         {
7783           *result = sr;
7784         }
7785     }
7786
7787   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7788
7789   return FALSE;
7790 }
7791
7792 /**
7793  * clutter_actor_get_preferred_width:
7794  * @self: A #ClutterActor
7795  * @for_height: available height when computing the preferred width,
7796  *   or a negative value to indicate that no height is defined
7797  * @min_width_p: (out) (allow-none): return location for minimum width,
7798  *   or %NULL
7799  * @natural_width_p: (out) (allow-none): return location for the natural
7800  *   width, or %NULL
7801  *
7802  * Computes the requested minimum and natural widths for an actor,
7803  * optionally depending on the specified height, or if they are
7804  * already computed, returns the cached values.
7805  *
7806  * An actor may not get its request - depending on the layout
7807  * manager that's in effect.
7808  *
7809  * A request should not incorporate the actor's scale or anchor point;
7810  * those transformations do not affect layout, only rendering.
7811  *
7812  * Since: 0.8
7813  */
7814 void
7815 clutter_actor_get_preferred_width (ClutterActor *self,
7816                                    gfloat        for_height,
7817                                    gfloat       *min_width_p,
7818                                    gfloat       *natural_width_p)
7819 {
7820   float request_min_width, request_natural_width;
7821   SizeRequest *cached_size_request;
7822   const ClutterLayoutInfo *info;
7823   ClutterActorPrivate *priv;
7824   gboolean found_in_cache;
7825
7826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7827
7828   priv = self->priv;
7829
7830   info = _clutter_actor_get_layout_info_or_defaults (self);
7831
7832   /* we shortcircuit the case of a fixed size set using set_width() */
7833   if (priv->min_width_set && priv->natural_width_set)
7834     {
7835       if (min_width_p != NULL)
7836         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7837
7838       if (natural_width_p != NULL)
7839         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7840
7841       return;
7842     }
7843
7844   /* the remaining cases are:
7845    *
7846    *   - either min_width or natural_width have been set
7847    *   - neither min_width or natural_width have been set
7848    *
7849    * in both cases, we go through the cache (and through the actor in case
7850    * of cache misses) and determine the authoritative value depending on
7851    * the *_set flags.
7852    */
7853
7854   if (!priv->needs_width_request)
7855     {
7856       found_in_cache =
7857         _clutter_actor_get_cached_size_request (for_height,
7858                                                 priv->width_requests,
7859                                                 &cached_size_request);
7860     }
7861   else
7862     {
7863       /* if the actor needs a width request we use the first slot */
7864       found_in_cache = FALSE;
7865       cached_size_request = &priv->width_requests[0];
7866     }
7867
7868   if (!found_in_cache)
7869     {
7870       gfloat minimum_width, natural_width;
7871       ClutterActorClass *klass;
7872
7873       minimum_width = natural_width = 0;
7874
7875       /* adjust for the margin */
7876       if (for_height >= 0)
7877         {
7878           for_height -= (info->margin.top + info->margin.bottom);
7879           if (for_height < 0)
7880             for_height = 0;
7881         }
7882
7883       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7884
7885       klass = CLUTTER_ACTOR_GET_CLASS (self);
7886       klass->get_preferred_width (self, for_height,
7887                                   &minimum_width,
7888                                   &natural_width);
7889
7890       /* adjust for the margin */
7891       minimum_width += (info->margin.left + info->margin.right);
7892       natural_width += (info->margin.left + info->margin.right);
7893
7894       /* Due to accumulated float errors, it's better not to warn
7895        * on this, but just fix it.
7896        */
7897       if (natural_width < minimum_width)
7898         natural_width = minimum_width;
7899
7900       cached_size_request->min_size = minimum_width;
7901       cached_size_request->natural_size = natural_width;
7902       cached_size_request->for_size = for_height;
7903       cached_size_request->age = priv->cached_width_age;
7904
7905       priv->cached_width_age += 1;
7906       priv->needs_width_request = FALSE;
7907     }
7908
7909   if (!priv->min_width_set)
7910     request_min_width = cached_size_request->min_size;
7911   else
7912     request_min_width = info->min_width;
7913
7914   if (!priv->natural_width_set)
7915     request_natural_width = cached_size_request->natural_size;
7916   else
7917     request_natural_width = info->natural_width;
7918
7919   if (min_width_p)
7920     *min_width_p = request_min_width;
7921
7922   if (natural_width_p)
7923     *natural_width_p = request_natural_width;
7924 }
7925
7926 /**
7927  * clutter_actor_get_preferred_height:
7928  * @self: A #ClutterActor
7929  * @for_width: available width to assume in computing desired height,
7930  *   or a negative value to indicate that no width is defined
7931  * @min_height_p: (out) (allow-none): return location for minimum height,
7932  *   or %NULL
7933  * @natural_height_p: (out) (allow-none): return location for natural
7934  *   height, or %NULL
7935  *
7936  * Computes the requested minimum and natural heights for an actor,
7937  * or if they are already computed, returns the cached values.
7938  *
7939  * An actor may not get its request - depending on the layout
7940  * manager that's in effect.
7941  *
7942  * A request should not incorporate the actor's scale or anchor point;
7943  * those transformations do not affect layout, only rendering.
7944  *
7945  * Since: 0.8
7946  */
7947 void
7948 clutter_actor_get_preferred_height (ClutterActor *self,
7949                                     gfloat        for_width,
7950                                     gfloat       *min_height_p,
7951                                     gfloat       *natural_height_p)
7952 {
7953   float request_min_height, request_natural_height;
7954   SizeRequest *cached_size_request;
7955   const ClutterLayoutInfo *info;
7956   ClutterActorPrivate *priv;
7957   gboolean found_in_cache;
7958
7959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7960
7961   priv = self->priv;
7962
7963   info = _clutter_actor_get_layout_info_or_defaults (self);
7964
7965   /* we shortcircuit the case of a fixed size set using set_height() */
7966   if (priv->min_height_set && priv->natural_height_set)
7967     {
7968       if (min_height_p != NULL)
7969         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7970
7971       if (natural_height_p != NULL)
7972         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7973
7974       return;
7975     }
7976
7977   /* the remaining cases are:
7978    *
7979    *   - either min_height or natural_height have been set
7980    *   - neither min_height or natural_height have been set
7981    *
7982    * in both cases, we go through the cache (and through the actor in case
7983    * of cache misses) and determine the authoritative value depending on
7984    * the *_set flags.
7985    */
7986
7987   if (!priv->needs_height_request)
7988     {
7989       found_in_cache =
7990         _clutter_actor_get_cached_size_request (for_width,
7991                                                 priv->height_requests,
7992                                                 &cached_size_request);
7993     }
7994   else
7995     {
7996       found_in_cache = FALSE;
7997       cached_size_request = &priv->height_requests[0];
7998     }
7999
8000   if (!found_in_cache)
8001     {
8002       gfloat minimum_height, natural_height;
8003       ClutterActorClass *klass;
8004
8005       minimum_height = natural_height = 0;
8006
8007       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8008
8009       /* adjust for margin */
8010       if (for_width >= 0)
8011         {
8012           for_width -= (info->margin.left + info->margin.right);
8013           if (for_width < 0)
8014             for_width = 0;
8015         }
8016
8017       klass = CLUTTER_ACTOR_GET_CLASS (self);
8018       klass->get_preferred_height (self, for_width,
8019                                    &minimum_height,
8020                                    &natural_height);
8021
8022       /* adjust for margin */
8023       minimum_height += (info->margin.top + info->margin.bottom);
8024       natural_height += (info->margin.top + info->margin.bottom);
8025
8026       /* Due to accumulated float errors, it's better not to warn
8027        * on this, but just fix it.
8028        */
8029       if (natural_height < minimum_height)
8030         natural_height = minimum_height;
8031
8032       cached_size_request->min_size = minimum_height;
8033       cached_size_request->natural_size = natural_height;
8034       cached_size_request->for_size = for_width;
8035       cached_size_request->age = priv->cached_height_age;
8036
8037       priv->cached_height_age += 1;
8038       priv->needs_height_request = FALSE;
8039     }
8040
8041   if (!priv->min_height_set)
8042     request_min_height = cached_size_request->min_size;
8043   else
8044     request_min_height = info->min_height;
8045
8046   if (!priv->natural_height_set)
8047     request_natural_height = cached_size_request->natural_size;
8048   else
8049     request_natural_height = info->natural_height;
8050
8051   if (min_height_p)
8052     *min_height_p = request_min_height;
8053
8054   if (natural_height_p)
8055     *natural_height_p = request_natural_height;
8056 }
8057
8058 /**
8059  * clutter_actor_get_allocation_box:
8060  * @self: A #ClutterActor
8061  * @box: (out): the function fills this in with the actor's allocation
8062  *
8063  * Gets the layout box an actor has been assigned. The allocation can
8064  * only be assumed valid inside a paint() method; anywhere else, it
8065  * may be out-of-date.
8066  *
8067  * An allocation does not incorporate the actor's scale or anchor point;
8068  * those transformations do not affect layout, only rendering.
8069  *
8070  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8071  * of functions inside the implementation of the get_preferred_width()
8072  * or get_preferred_height() virtual functions.</note>
8073  *
8074  * Since: 0.8
8075  */
8076 void
8077 clutter_actor_get_allocation_box (ClutterActor    *self,
8078                                   ClutterActorBox *box)
8079 {
8080   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8081
8082   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8083    * which limits calling get_allocation to inside paint() basically; or
8084    * we can 2) force a layout, which could be expensive if someone calls
8085    * get_allocation somewhere silly; or we can 3) just return the latest
8086    * value, allowing it to be out-of-date, and assume people know what
8087    * they are doing.
8088    *
8089    * The least-surprises approach that keeps existing code working is
8090    * likely to be 2). People can end up doing some inefficient things,
8091    * though, and in general code that requires 2) is probably broken.
8092    */
8093
8094   /* this implements 2) */
8095   if (G_UNLIKELY (self->priv->needs_allocation))
8096     {
8097       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8098
8099       /* do not queue a relayout on an unparented actor */
8100       if (stage)
8101         _clutter_stage_maybe_relayout (stage);
8102     }
8103
8104   /* commenting out the code above and just keeping this assigment
8105    * implements 3)
8106    */
8107   *box = self->priv->allocation;
8108 }
8109
8110 /**
8111  * clutter_actor_get_allocation_geometry:
8112  * @self: A #ClutterActor
8113  * @geom: (out): allocation geometry in pixels
8114  *
8115  * Gets the layout box an actor has been assigned.  The allocation can
8116  * only be assumed valid inside a paint() method; anywhere else, it
8117  * may be out-of-date.
8118  *
8119  * An allocation does not incorporate the actor's scale or anchor point;
8120  * those transformations do not affect layout, only rendering.
8121  *
8122  * The returned rectangle is in pixels.
8123  *
8124  * Since: 0.8
8125  */
8126 void
8127 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8128                                        ClutterGeometry *geom)
8129 {
8130   ClutterActorBox box;
8131
8132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8133   g_return_if_fail (geom != NULL);
8134
8135   clutter_actor_get_allocation_box (self, &box);
8136
8137   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8138   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8139   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8140   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8141 }
8142
8143 static void
8144 clutter_actor_update_constraints (ClutterActor    *self,
8145                                   ClutterActorBox *allocation)
8146 {
8147   ClutterActorPrivate *priv = self->priv;
8148   const GList *constraints, *l;
8149
8150   if (priv->constraints == NULL)
8151     return;
8152
8153   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8154   for (l = constraints; l != NULL; l = l->next)
8155     {
8156       ClutterConstraint *constraint = l->data;
8157       ClutterActorMeta *meta = l->data;
8158
8159       if (clutter_actor_meta_get_enabled (meta))
8160         {
8161           _clutter_constraint_update_allocation (constraint,
8162                                                  self,
8163                                                  allocation);
8164
8165           CLUTTER_NOTE (LAYOUT,
8166                         "Allocation of '%s' after constraint '%s': "
8167                         "{ %.2f, %.2f, %.2f, %.2f }",
8168                         _clutter_actor_get_debug_name (self),
8169                         _clutter_actor_meta_get_debug_name (meta),
8170                         allocation->x1,
8171                         allocation->y1,
8172                         allocation->x2,
8173                         allocation->y2);
8174         }
8175     }
8176 }
8177
8178 /*< private >
8179  * clutter_actor_adjust_allocation:
8180  * @self: a #ClutterActor
8181  * @allocation: (inout): the allocation to adjust
8182  *
8183  * Adjusts the passed allocation box taking into account the actor's
8184  * layout information, like alignment, expansion, and margin.
8185  */
8186 static void
8187 clutter_actor_adjust_allocation (ClutterActor    *self,
8188                                  ClutterActorBox *allocation)
8189 {
8190   ClutterActorBox adj_allocation;
8191   float alloc_width, alloc_height;
8192   float min_width, min_height;
8193   float nat_width, nat_height;
8194   ClutterRequestMode req_mode;
8195
8196   adj_allocation = *allocation;
8197
8198   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8199
8200   /* we want to hit the cache, so we use the public API */
8201   req_mode = clutter_actor_get_request_mode (self);
8202
8203   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8204     {
8205       clutter_actor_get_preferred_width (self, -1,
8206                                          &min_width,
8207                                          &nat_width);
8208       clutter_actor_get_preferred_height (self, alloc_width,
8209                                           &min_height,
8210                                           &nat_height);
8211     }
8212   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8213     {
8214       clutter_actor_get_preferred_height (self, -1,
8215                                           &min_height,
8216                                           &nat_height);
8217       clutter_actor_get_preferred_height (self, alloc_height,
8218                                           &min_width,
8219                                           &nat_width);
8220     }
8221
8222 #ifdef CLUTTER_ENABLE_DEBUG
8223   /* warn about underallocations */
8224   if (_clutter_diagnostic_enabled () &&
8225       (floorf (min_width - alloc_width) > 0 ||
8226        floorf (min_height - alloc_height) > 0))
8227     {
8228       ClutterActor *parent = clutter_actor_get_parent (self);
8229
8230       /* the only actors that are allowed to be underallocated are the Stage,
8231        * as it doesn't have an implicit size, and Actors that specifically
8232        * told us that they want to opt-out from layout control mechanisms
8233        * through the NO_LAYOUT escape hatch.
8234        */
8235       if (parent != NULL &&
8236           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8237         {
8238           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8239                      "of %.2f x %.2f from its parent actor '%s', but its "
8240                      "requested minimum size is of %.2f x %.2f",
8241                      _clutter_actor_get_debug_name (self),
8242                      alloc_width, alloc_height,
8243                      _clutter_actor_get_debug_name (parent),
8244                      min_width, min_height);
8245         }
8246     }
8247 #endif
8248
8249   clutter_actor_adjust_width (self,
8250                               &min_width,
8251                               &nat_width,
8252                               &adj_allocation.x1,
8253                               &adj_allocation.x2);
8254
8255   clutter_actor_adjust_height (self,
8256                                &min_height,
8257                                &nat_height,
8258                                &adj_allocation.y1,
8259                                &adj_allocation.y2);
8260
8261   /* we maintain the invariant that an allocation cannot be adjusted
8262    * to be outside the parent-given box
8263    */
8264   if (adj_allocation.x1 < allocation->x1 ||
8265       adj_allocation.y1 < allocation->y1 ||
8266       adj_allocation.x2 > allocation->x2 ||
8267       adj_allocation.y2 > allocation->y2)
8268     {
8269       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8270                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8271                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8272                  _clutter_actor_get_debug_name (self),
8273                  adj_allocation.x1, adj_allocation.y1,
8274                  adj_allocation.x2 - adj_allocation.x1,
8275                  adj_allocation.y2 - adj_allocation.y1,
8276                  allocation->x1, allocation->y1,
8277                  allocation->x2 - allocation->x1,
8278                  allocation->y2 - allocation->y1);
8279       return;
8280     }
8281
8282   *allocation = adj_allocation;
8283 }
8284
8285 /**
8286  * clutter_actor_allocate:
8287  * @self: A #ClutterActor
8288  * @box: new allocation of the actor, in parent-relative coordinates
8289  * @flags: flags that control the allocation
8290  *
8291  * Called by the parent of an actor to assign the actor its size.
8292  * Should never be called by applications (except when implementing
8293  * a container or layout manager).
8294  *
8295  * Actors can know from their allocation box whether they have moved
8296  * with respect to their parent actor. The @flags parameter describes
8297  * additional information about the allocation, for instance whether
8298  * the parent has moved with respect to the stage, for example because
8299  * a grandparent's origin has moved.
8300  *
8301  * Since: 0.8
8302  */
8303 void
8304 clutter_actor_allocate (ClutterActor           *self,
8305                         const ClutterActorBox  *box,
8306                         ClutterAllocationFlags  flags)
8307 {
8308   ClutterActorPrivate *priv;
8309   ClutterActorClass *klass;
8310   ClutterActorBox old_allocation, real_allocation;
8311   gboolean origin_changed, child_moved, size_changed;
8312   gboolean stage_allocation_changed;
8313
8314   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8315   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8316     {
8317       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8318                  "which isn't a descendent of the stage!\n",
8319                  self, _clutter_actor_get_debug_name (self));
8320       return;
8321     }
8322
8323   priv = self->priv;
8324
8325   old_allocation = priv->allocation;
8326   real_allocation = *box;
8327
8328   /* constraints are allowed to modify the allocation only here; we do
8329    * this prior to all the other checks so that we can bail out if the
8330    * allocation did not change
8331    */
8332   clutter_actor_update_constraints (self, &real_allocation);
8333
8334   /* adjust the allocation depending on the align/margin properties */
8335   clutter_actor_adjust_allocation (self, &real_allocation);
8336
8337   if (real_allocation.x2 < real_allocation.x1 ||
8338       real_allocation.y2 < real_allocation.y1)
8339     {
8340       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8341                  _clutter_actor_get_debug_name (self),
8342                  real_allocation.x2 - real_allocation.x1,
8343                  real_allocation.y2 - real_allocation.y1);
8344     }
8345
8346   /* we allow 0-sized actors, but not negative-sized ones */
8347   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8348   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8349
8350   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8351
8352   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8353                  real_allocation.y1 != old_allocation.y1);
8354
8355   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8356                   real_allocation.y2 != old_allocation.y2);
8357
8358   if (origin_changed || child_moved || size_changed)
8359     stage_allocation_changed = TRUE;
8360   else
8361     stage_allocation_changed = FALSE;
8362
8363   /* If we get an allocation "out of the blue"
8364    * (we did not queue relayout), then we want to
8365    * ignore it. But if we have needs_allocation set,
8366    * we want to guarantee that allocate() virtual
8367    * method is always called, i.e. that queue_relayout()
8368    * always results in an allocate() invocation on
8369    * an actor.
8370    *
8371    * The optimization here is to avoid re-allocating
8372    * actors that did not queue relayout and were
8373    * not moved.
8374    */
8375   if (!priv->needs_allocation && !stage_allocation_changed)
8376     {
8377       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8378       return;
8379     }
8380
8381   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8382    * clutter_actor_allocate(), it indicates whether the parent has its
8383    * absolute origin moved; when passed in to ClutterActor::allocate()
8384    * virtual method though, it indicates whether the child has its
8385    * absolute origin moved.  So we set it when child_moved is TRUE
8386    */
8387   if (child_moved)
8388     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8389
8390   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8391
8392   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8393                 _clutter_actor_get_debug_name (self));
8394
8395   klass = CLUTTER_ACTOR_GET_CLASS (self);
8396   klass->allocate (self, &real_allocation, flags);
8397
8398   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8399
8400   if (stage_allocation_changed)
8401     clutter_actor_queue_redraw (self);
8402 }
8403
8404 /**
8405  * clutter_actor_set_allocation:
8406  * @self: a #ClutterActor
8407  * @box: a #ClutterActorBox
8408  * @flags: allocation flags
8409  *
8410  * Stores the allocation of @self as defined by @box.
8411  *
8412  * This function can only be called from within the implementation of
8413  * the #ClutterActorClass.allocate() virtual function.
8414  *
8415  * The allocation should have been adjusted to take into account constraints,
8416  * alignment, and margin properties. If you are implementing a #ClutterActor
8417  * subclass that provides its own layout management policy for its children
8418  * instead of using a #ClutterLayoutManager delegate, you should not call
8419  * this function on the children of @self; instead, you should call
8420  * clutter_actor_allocate(), which will adjust the allocation box for
8421  * you.
8422  *
8423  * This function should only be used by subclasses of #ClutterActor
8424  * that wish to store their allocation but cannot chain up to the
8425  * parent's implementation; the default implementation of the
8426  * #ClutterActorClass.allocate() virtual function will call this
8427  * function.
8428  *
8429  * It is important to note that, while chaining up was the recommended
8430  * behaviour for #ClutterActor subclasses prior to the introduction of
8431  * this function, it is recommended to call clutter_actor_set_allocation()
8432  * instead.
8433  *
8434  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8435  * to handle the allocation of its children, this function will call
8436  * the clutter_layout_manager_allocate() function only if the
8437  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8438  * expected that the subclass will call clutter_layout_manager_allocate()
8439  * by itself. For instance, the following code:
8440  *
8441  * |[
8442  * static void
8443  * my_actor_allocate (ClutterActor *actor,
8444  *                    const ClutterActorBox *allocation,
8445  *                    ClutterAllocationFlags flags)
8446  * {
8447  *   ClutterActorBox new_alloc;
8448  *   ClutterAllocationFlags new_flags;
8449  *
8450  *   adjust_allocation (allocation, &amp;new_alloc);
8451  *
8452  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8453  *
8454  *   /&ast; this will use the layout manager set on the actor &ast;/
8455  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8456  * }
8457  * ]|
8458  *
8459  * is equivalent to this:
8460  *
8461  * |[
8462  * static void
8463  * my_actor_allocate (ClutterActor *actor,
8464  *                    const ClutterActorBox *allocation,
8465  *                    ClutterAllocationFlags flags)
8466  * {
8467  *   ClutterLayoutManager *layout;
8468  *   ClutterActorBox new_alloc;
8469  *
8470  *   adjust_allocation (allocation, &amp;new_alloc);
8471  *
8472  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8473  *
8474  *   layout = clutter_actor_get_layout_manager (actor);
8475  *   clutter_layout_manager_allocate (layout,
8476  *                                    CLUTTER_CONTAINER (actor),
8477  *                                    &amp;new_alloc,
8478  *                                    flags);
8479  * }
8480  * ]|
8481  *
8482  * Since: 1.10
8483  */
8484 void
8485 clutter_actor_set_allocation (ClutterActor           *self,
8486                               const ClutterActorBox  *box,
8487                               ClutterAllocationFlags  flags)
8488 {
8489   ClutterActorPrivate *priv;
8490   gboolean changed;
8491
8492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8493   g_return_if_fail (box != NULL);
8494
8495   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8496     {
8497       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8498                   "can only be called from within the implementation of "
8499                   "the ClutterActor::allocate() virtual function.");
8500       return;
8501     }
8502
8503   priv = self->priv;
8504
8505   g_object_freeze_notify (G_OBJECT (self));
8506
8507   changed = clutter_actor_set_allocation_internal (self, box, flags);
8508
8509   /* we allocate our children before we notify changes in our geometry,
8510    * so that people connecting to properties will be able to get valid
8511    * data out of the sub-tree of the scene graph that has this actor at
8512    * the root.
8513    */
8514   clutter_actor_maybe_layout_children (self, box, flags);
8515
8516   if (changed)
8517     {
8518       ClutterActorBox signal_box = priv->allocation;
8519       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8520
8521       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8522                      &signal_box,
8523                      signal_flags);
8524     }
8525
8526   g_object_thaw_notify (G_OBJECT (self));
8527 }
8528
8529 /**
8530  * clutter_actor_set_geometry:
8531  * @self: A #ClutterActor
8532  * @geometry: A #ClutterGeometry
8533  *
8534  * Sets the actor's fixed position and forces its minimum and natural
8535  * size, in pixels. This means the untransformed actor will have the
8536  * given geometry. This is the same as calling clutter_actor_set_position()
8537  * and clutter_actor_set_size().
8538  *
8539  * Deprecated: 1.10: Use clutter_actor_set_position() and
8540  *   clutter_actor_set_size() instead.
8541  */
8542 void
8543 clutter_actor_set_geometry (ClutterActor          *self,
8544                             const ClutterGeometry *geometry)
8545 {
8546   g_object_freeze_notify (G_OBJECT (self));
8547
8548   clutter_actor_set_position (self, geometry->x, geometry->y);
8549   clutter_actor_set_size (self, geometry->width, geometry->height);
8550
8551   g_object_thaw_notify (G_OBJECT (self));
8552 }
8553
8554 /**
8555  * clutter_actor_get_geometry:
8556  * @self: A #ClutterActor
8557  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8558  *
8559  * Gets the size and position of an actor relative to its parent
8560  * actor. This is the same as calling clutter_actor_get_position() and
8561  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8562  * requested size and position if the actor's allocation is invalid.
8563  *
8564  * Deprecated: 1.10: Use clutter_actor_get_position() and
8565  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8566  *   instead.
8567  */
8568 void
8569 clutter_actor_get_geometry (ClutterActor    *self,
8570                             ClutterGeometry *geometry)
8571 {
8572   gfloat x, y, width, height;
8573
8574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8575   g_return_if_fail (geometry != NULL);
8576
8577   clutter_actor_get_position (self, &x, &y);
8578   clutter_actor_get_size (self, &width, &height);
8579
8580   geometry->x = (int) x;
8581   geometry->y = (int) y;
8582   geometry->width = (int) width;
8583   geometry->height = (int) height;
8584 }
8585
8586 /**
8587  * clutter_actor_set_position:
8588  * @self: A #ClutterActor
8589  * @x: New left position of actor in pixels.
8590  * @y: New top position of actor in pixels.
8591  *
8592  * Sets the actor's fixed position in pixels relative to any parent
8593  * actor.
8594  *
8595  * If a layout manager is in use, this position will override the
8596  * layout manager and force a fixed position.
8597  */
8598 void
8599 clutter_actor_set_position (ClutterActor *self,
8600                             gfloat        x,
8601                             gfloat        y)
8602 {
8603   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8604
8605   g_object_freeze_notify (G_OBJECT (self));
8606
8607   clutter_actor_set_x (self, x);
8608   clutter_actor_set_y (self, y);
8609
8610   g_object_thaw_notify (G_OBJECT (self));
8611 }
8612
8613 /**
8614  * clutter_actor_get_fixed_position_set:
8615  * @self: A #ClutterActor
8616  *
8617  * Checks whether an actor has a fixed position set (and will thus be
8618  * unaffected by any layout manager).
8619  *
8620  * Return value: %TRUE if the fixed position is set on the actor
8621  *
8622  * Since: 0.8
8623  */
8624 gboolean
8625 clutter_actor_get_fixed_position_set (ClutterActor *self)
8626 {
8627   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8628
8629   return self->priv->position_set;
8630 }
8631
8632 /**
8633  * clutter_actor_set_fixed_position_set:
8634  * @self: A #ClutterActor
8635  * @is_set: whether to use fixed position
8636  *
8637  * Sets whether an actor has a fixed position set (and will thus be
8638  * unaffected by any layout manager).
8639  *
8640  * Since: 0.8
8641  */
8642 void
8643 clutter_actor_set_fixed_position_set (ClutterActor *self,
8644                                       gboolean      is_set)
8645 {
8646   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8647
8648   if (self->priv->position_set == (is_set != FALSE))
8649     return;
8650
8651   self->priv->position_set = is_set != FALSE;
8652   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8653
8654   clutter_actor_queue_relayout (self);
8655 }
8656
8657 /**
8658  * clutter_actor_move_by:
8659  * @self: A #ClutterActor
8660  * @dx: Distance to move Actor on X axis.
8661  * @dy: Distance to move Actor on Y axis.
8662  *
8663  * Moves an actor by the specified distance relative to its current
8664  * position in pixels.
8665  *
8666  * This function modifies the fixed position of an actor and thus removes
8667  * it from any layout management. Another way to move an actor is with an
8668  * anchor point, see clutter_actor_set_anchor_point().
8669  *
8670  * Since: 0.2
8671  */
8672 void
8673 clutter_actor_move_by (ClutterActor *self,
8674                        gfloat        dx,
8675                        gfloat        dy)
8676 {
8677   const ClutterLayoutInfo *info;
8678   gfloat x, y;
8679
8680   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8681
8682   info = _clutter_actor_get_layout_info_or_defaults (self);
8683   x = info->fixed_x;
8684   y = info->fixed_y;
8685
8686   clutter_actor_set_position (self, x + dx, y + dy);
8687 }
8688
8689 static void
8690 clutter_actor_set_min_width (ClutterActor *self,
8691                              gfloat        min_width)
8692 {
8693   ClutterActorPrivate *priv = self->priv;
8694   ClutterActorBox old = { 0, };
8695   ClutterLayoutInfo *info;
8696
8697   /* if we are setting the size on a top-level actor and the
8698    * backend only supports static top-levels (e.g. framebuffers)
8699    * then we ignore the passed value and we override it with
8700    * the stage implementation's preferred size.
8701    */
8702   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8703       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8704     return;
8705
8706   info = _clutter_actor_get_layout_info (self);
8707
8708   if (priv->min_width_set && min_width == info->min_width)
8709     return;
8710
8711   g_object_freeze_notify (G_OBJECT (self));
8712
8713   clutter_actor_store_old_geometry (self, &old);
8714
8715   info->min_width = min_width;
8716   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8717   clutter_actor_set_min_width_set (self, TRUE);
8718
8719   clutter_actor_notify_if_geometry_changed (self, &old);
8720
8721   g_object_thaw_notify (G_OBJECT (self));
8722
8723   clutter_actor_queue_relayout (self);
8724 }
8725
8726 static void
8727 clutter_actor_set_min_height (ClutterActor *self,
8728                               gfloat        min_height)
8729
8730 {
8731   ClutterActorPrivate *priv = self->priv;
8732   ClutterActorBox old = { 0, };
8733   ClutterLayoutInfo *info;
8734
8735   /* if we are setting the size on a top-level actor and the
8736    * backend only supports static top-levels (e.g. framebuffers)
8737    * then we ignore the passed value and we override it with
8738    * the stage implementation's preferred size.
8739    */
8740   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8741       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8742     return;
8743
8744   info = _clutter_actor_get_layout_info (self);
8745
8746   if (priv->min_height_set && min_height == info->min_height)
8747     return;
8748
8749   g_object_freeze_notify (G_OBJECT (self));
8750
8751   clutter_actor_store_old_geometry (self, &old);
8752
8753   info->min_height = min_height;
8754   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8755   clutter_actor_set_min_height_set (self, TRUE);
8756
8757   clutter_actor_notify_if_geometry_changed (self, &old);
8758
8759   g_object_thaw_notify (G_OBJECT (self));
8760
8761   clutter_actor_queue_relayout (self);
8762 }
8763
8764 static void
8765 clutter_actor_set_natural_width (ClutterActor *self,
8766                                  gfloat        natural_width)
8767 {
8768   ClutterActorPrivate *priv = self->priv;
8769   ClutterActorBox old = { 0, };
8770   ClutterLayoutInfo *info;
8771
8772   /* if we are setting the size on a top-level actor and the
8773    * backend only supports static top-levels (e.g. framebuffers)
8774    * then we ignore the passed value and we override it with
8775    * the stage implementation's preferred size.
8776    */
8777   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8778       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8779     return;
8780
8781   info = _clutter_actor_get_layout_info (self);
8782
8783   if (priv->natural_width_set && natural_width == info->natural_width)
8784     return;
8785
8786   g_object_freeze_notify (G_OBJECT (self));
8787
8788   clutter_actor_store_old_geometry (self, &old);
8789
8790   info->natural_width = natural_width;
8791   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8792   clutter_actor_set_natural_width_set (self, TRUE);
8793
8794   clutter_actor_notify_if_geometry_changed (self, &old);
8795
8796   g_object_thaw_notify (G_OBJECT (self));
8797
8798   clutter_actor_queue_relayout (self);
8799 }
8800
8801 static void
8802 clutter_actor_set_natural_height (ClutterActor *self,
8803                                   gfloat        natural_height)
8804 {
8805   ClutterActorPrivate *priv = self->priv;
8806   ClutterActorBox old = { 0, };
8807   ClutterLayoutInfo *info;
8808
8809   /* if we are setting the size on a top-level actor and the
8810    * backend only supports static top-levels (e.g. framebuffers)
8811    * then we ignore the passed value and we override it with
8812    * the stage implementation's preferred size.
8813    */
8814   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8815       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8816     return;
8817
8818   info = _clutter_actor_get_layout_info (self);
8819
8820   if (priv->natural_height_set && natural_height == info->natural_height)
8821     return;
8822
8823   g_object_freeze_notify (G_OBJECT (self));
8824
8825   clutter_actor_store_old_geometry (self, &old);
8826
8827   info->natural_height = natural_height;
8828   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8829   clutter_actor_set_natural_height_set (self, TRUE);
8830
8831   clutter_actor_notify_if_geometry_changed (self, &old);
8832
8833   g_object_thaw_notify (G_OBJECT (self));
8834
8835   clutter_actor_queue_relayout (self);
8836 }
8837
8838 static void
8839 clutter_actor_set_min_width_set (ClutterActor *self,
8840                                  gboolean      use_min_width)
8841 {
8842   ClutterActorPrivate *priv = self->priv;
8843   ClutterActorBox old = { 0, };
8844
8845   if (priv->min_width_set == (use_min_width != FALSE))
8846     return;
8847
8848   clutter_actor_store_old_geometry (self, &old);
8849
8850   priv->min_width_set = use_min_width != FALSE;
8851   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8852
8853   clutter_actor_notify_if_geometry_changed (self, &old);
8854
8855   clutter_actor_queue_relayout (self);
8856 }
8857
8858 static void
8859 clutter_actor_set_min_height_set (ClutterActor *self,
8860                                   gboolean      use_min_height)
8861 {
8862   ClutterActorPrivate *priv = self->priv;
8863   ClutterActorBox old = { 0, };
8864
8865   if (priv->min_height_set == (use_min_height != FALSE))
8866     return;
8867
8868   clutter_actor_store_old_geometry (self, &old);
8869
8870   priv->min_height_set = use_min_height != FALSE;
8871   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8872
8873   clutter_actor_notify_if_geometry_changed (self, &old);
8874
8875   clutter_actor_queue_relayout (self);
8876 }
8877
8878 static void
8879 clutter_actor_set_natural_width_set (ClutterActor *self,
8880                                      gboolean      use_natural_width)
8881 {
8882   ClutterActorPrivate *priv = self->priv;
8883   ClutterActorBox old = { 0, };
8884
8885   if (priv->natural_width_set == (use_natural_width != FALSE))
8886     return;
8887
8888   clutter_actor_store_old_geometry (self, &old);
8889
8890   priv->natural_width_set = use_natural_width != FALSE;
8891   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8892
8893   clutter_actor_notify_if_geometry_changed (self, &old);
8894
8895   clutter_actor_queue_relayout (self);
8896 }
8897
8898 static void
8899 clutter_actor_set_natural_height_set (ClutterActor *self,
8900                                       gboolean      use_natural_height)
8901 {
8902   ClutterActorPrivate *priv = self->priv;
8903   ClutterActorBox old = { 0, };
8904
8905   if (priv->natural_height_set == (use_natural_height != FALSE))
8906     return;
8907
8908   clutter_actor_store_old_geometry (self, &old);
8909
8910   priv->natural_height_set = use_natural_height != FALSE;
8911   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8912
8913   clutter_actor_notify_if_geometry_changed (self, &old);
8914
8915   clutter_actor_queue_relayout (self);
8916 }
8917
8918 /**
8919  * clutter_actor_set_request_mode:
8920  * @self: a #ClutterActor
8921  * @mode: the request mode
8922  *
8923  * Sets the geometry request mode of @self.
8924  *
8925  * The @mode determines the order for invoking
8926  * clutter_actor_get_preferred_width() and
8927  * clutter_actor_get_preferred_height()
8928  *
8929  * Since: 1.2
8930  */
8931 void
8932 clutter_actor_set_request_mode (ClutterActor       *self,
8933                                 ClutterRequestMode  mode)
8934 {
8935   ClutterActorPrivate *priv;
8936
8937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8938
8939   priv = self->priv;
8940
8941   if (priv->request_mode == mode)
8942     return;
8943
8944   priv->request_mode = mode;
8945
8946   priv->needs_width_request = TRUE;
8947   priv->needs_height_request = TRUE;
8948
8949   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8950
8951   clutter_actor_queue_relayout (self);
8952 }
8953
8954 /**
8955  * clutter_actor_get_request_mode:
8956  * @self: a #ClutterActor
8957  *
8958  * Retrieves the geometry request mode of @self
8959  *
8960  * Return value: the request mode for the actor
8961  *
8962  * Since: 1.2
8963  */
8964 ClutterRequestMode
8965 clutter_actor_get_request_mode (ClutterActor *self)
8966 {
8967   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8968                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8969
8970   return self->priv->request_mode;
8971 }
8972
8973 /* variant of set_width() without checks and without notification
8974  * freeze+thaw, for internal usage only
8975  */
8976 static inline void
8977 clutter_actor_set_width_internal (ClutterActor *self,
8978                                   gfloat        width)
8979 {
8980   if (width >= 0)
8981     {
8982       /* the Stage will use the :min-width to control the minimum
8983        * width to be resized to, so we should not be setting it
8984        * along with the :natural-width
8985        */
8986       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8987         clutter_actor_set_min_width (self, width);
8988
8989       clutter_actor_set_natural_width (self, width);
8990     }
8991   else
8992     {
8993       /* we only unset the :natural-width for the Stage */
8994       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8995         clutter_actor_set_min_width_set (self, FALSE);
8996
8997       clutter_actor_set_natural_width_set (self, FALSE);
8998     }
8999 }
9000
9001 /* variant of set_height() without checks and without notification
9002  * freeze+thaw, for internal usage only
9003  */
9004 static inline void
9005 clutter_actor_set_height_internal (ClutterActor *self,
9006                                    gfloat        height)
9007 {
9008   if (height >= 0)
9009     {
9010       /* see the comment above in set_width_internal() */
9011       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9012         clutter_actor_set_min_height (self, height);
9013
9014       clutter_actor_set_natural_height (self, height);
9015     }
9016   else
9017     {
9018       /* see the comment above in set_width_internal() */
9019       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9020         clutter_actor_set_min_height_set (self, FALSE);
9021
9022       clutter_actor_set_natural_height_set (self, FALSE);
9023     }
9024 }
9025
9026 /**
9027  * clutter_actor_set_size:
9028  * @self: A #ClutterActor
9029  * @width: New width of actor in pixels, or -1
9030  * @height: New height of actor in pixels, or -1
9031  *
9032  * Sets the actor's size request in pixels. This overrides any
9033  * "normal" size request the actor would have. For example
9034  * a text actor might normally request the size of the text;
9035  * this function would force a specific size instead.
9036  *
9037  * If @width and/or @height are -1 the actor will use its
9038  * "normal" size request instead of overriding it, i.e.
9039  * you can "unset" the size with -1.
9040  *
9041  * This function sets or unsets both the minimum and natural size.
9042  */
9043 void
9044 clutter_actor_set_size (ClutterActor *self,
9045                         gfloat        width,
9046                         gfloat        height)
9047 {
9048   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9049
9050   g_object_freeze_notify (G_OBJECT (self));
9051
9052   clutter_actor_set_width (self, width);
9053   clutter_actor_set_height (self, height);
9054
9055   g_object_thaw_notify (G_OBJECT (self));
9056 }
9057
9058 /**
9059  * clutter_actor_get_size:
9060  * @self: A #ClutterActor
9061  * @width: (out) (allow-none): return location for the width, or %NULL.
9062  * @height: (out) (allow-none): return location for the height, or %NULL.
9063  *
9064  * This function tries to "do what you mean" and return
9065  * the size an actor will have. If the actor has a valid
9066  * allocation, the allocation will be returned; otherwise,
9067  * the actors natural size request will be returned.
9068  *
9069  * If you care whether you get the request vs. the allocation, you
9070  * should probably call a different function like
9071  * clutter_actor_get_allocation_box() or
9072  * clutter_actor_get_preferred_width().
9073  *
9074  * Since: 0.2
9075  */
9076 void
9077 clutter_actor_get_size (ClutterActor *self,
9078                         gfloat       *width,
9079                         gfloat       *height)
9080 {
9081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9082
9083   if (width)
9084     *width = clutter_actor_get_width (self);
9085
9086   if (height)
9087     *height = clutter_actor_get_height (self);
9088 }
9089
9090 /**
9091  * clutter_actor_get_position:
9092  * @self: a #ClutterActor
9093  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9094  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9095  *
9096  * This function tries to "do what you mean" and tell you where the
9097  * actor is, prior to any transformations. Retrieves the fixed
9098  * position of an actor in pixels, if one has been set; otherwise, if
9099  * the allocation is valid, returns the actor's allocated position;
9100  * otherwise, returns 0,0.
9101  *
9102  * The returned position is in pixels.
9103  *
9104  * Since: 0.6
9105  */
9106 void
9107 clutter_actor_get_position (ClutterActor *self,
9108                             gfloat       *x,
9109                             gfloat       *y)
9110 {
9111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9112
9113   if (x)
9114     *x = clutter_actor_get_x (self);
9115
9116   if (y)
9117     *y = clutter_actor_get_y (self);
9118 }
9119
9120 /**
9121  * clutter_actor_get_transformed_position:
9122  * @self: A #ClutterActor
9123  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9124  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9125  *
9126  * Gets the absolute position of an actor, in pixels relative to the stage.
9127  *
9128  * Since: 0.8
9129  */
9130 void
9131 clutter_actor_get_transformed_position (ClutterActor *self,
9132                                         gfloat       *x,
9133                                         gfloat       *y)
9134 {
9135   ClutterVertex v1;
9136   ClutterVertex v2;
9137
9138   v1.x = v1.y = v1.z = 0;
9139   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9140
9141   if (x)
9142     *x = v2.x;
9143
9144   if (y)
9145     *y = v2.y;
9146 }
9147
9148 /**
9149  * clutter_actor_get_transformed_size:
9150  * @self: A #ClutterActor
9151  * @width: (out) (allow-none): return location for the width, or %NULL
9152  * @height: (out) (allow-none): return location for the height, or %NULL
9153  *
9154  * Gets the absolute size of an actor in pixels, taking into account the
9155  * scaling factors.
9156  *
9157  * If the actor has a valid allocation, the allocated size will be used.
9158  * If the actor has not a valid allocation then the preferred size will
9159  * be transformed and returned.
9160  *
9161  * If you want the transformed allocation, see
9162  * clutter_actor_get_abs_allocation_vertices() instead.
9163  *
9164  * <note>When the actor (or one of its ancestors) is rotated around the
9165  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9166  * as a generic quadrangle; in that case this function returns the size
9167  * of the smallest rectangle that encapsulates the entire quad. Please
9168  * note that in this case no assumptions can be made about the relative
9169  * position of this envelope to the absolute position of the actor, as
9170  * returned by clutter_actor_get_transformed_position(); if you need this
9171  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9172  * to get the coords of the actual quadrangle.</note>
9173  *
9174  * Since: 0.8
9175  */
9176 void
9177 clutter_actor_get_transformed_size (ClutterActor *self,
9178                                     gfloat       *width,
9179                                     gfloat       *height)
9180 {
9181   ClutterActorPrivate *priv;
9182   ClutterVertex v[4];
9183   gfloat x_min, x_max, y_min, y_max;
9184   gint i;
9185
9186   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9187
9188   priv = self->priv;
9189
9190   /* if the actor hasn't been allocated yet, get the preferred
9191    * size and transform that
9192    */
9193   if (priv->needs_allocation)
9194     {
9195       gfloat natural_width, natural_height;
9196       ClutterActorBox box;
9197
9198       /* Make a fake allocation to transform.
9199        *
9200        * NB: _clutter_actor_transform_and_project_box expects a box in
9201        * the actor's coordinate space... */
9202
9203       box.x1 = 0;
9204       box.y1 = 0;
9205
9206       natural_width = natural_height = 0;
9207       clutter_actor_get_preferred_size (self, NULL, NULL,
9208                                         &natural_width,
9209                                         &natural_height);
9210
9211       box.x2 = natural_width;
9212       box.y2 = natural_height;
9213
9214       _clutter_actor_transform_and_project_box (self, &box, v);
9215     }
9216   else
9217     clutter_actor_get_abs_allocation_vertices (self, v);
9218
9219   x_min = x_max = v[0].x;
9220   y_min = y_max = v[0].y;
9221
9222   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9223     {
9224       if (v[i].x < x_min)
9225         x_min = v[i].x;
9226
9227       if (v[i].x > x_max)
9228         x_max = v[i].x;
9229
9230       if (v[i].y < y_min)
9231         y_min = v[i].y;
9232
9233       if (v[i].y > y_max)
9234         y_max = v[i].y;
9235     }
9236
9237   if (width)
9238     *width  = x_max - x_min;
9239
9240   if (height)
9241     *height = y_max - y_min;
9242 }
9243
9244 /**
9245  * clutter_actor_get_width:
9246  * @self: A #ClutterActor
9247  *
9248  * Retrieves the width of a #ClutterActor.
9249  *
9250  * If the actor has a valid allocation, this function will return the
9251  * width of the allocated area given to the actor.
9252  *
9253  * If the actor does not have a valid allocation, this function will
9254  * return the actor's natural width, that is the preferred width of
9255  * the actor.
9256  *
9257  * If you care whether you get the preferred width or the width that
9258  * has been assigned to the actor, you should probably call a different
9259  * function like clutter_actor_get_allocation_box() to retrieve the
9260  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9261  * preferred width.
9262  *
9263  * If an actor has a fixed width, for instance a width that has been
9264  * assigned using clutter_actor_set_width(), the width returned will
9265  * be the same value.
9266  *
9267  * Return value: the width of the actor, in pixels
9268  */
9269 gfloat
9270 clutter_actor_get_width (ClutterActor *self)
9271 {
9272   ClutterActorPrivate *priv;
9273
9274   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9275
9276   priv = self->priv;
9277
9278   if (priv->needs_allocation)
9279     {
9280       gfloat natural_width = 0;
9281
9282       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9283         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9284       else
9285         {
9286           gfloat natural_height = 0;
9287
9288           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9289           clutter_actor_get_preferred_width (self, natural_height,
9290                                              NULL,
9291                                              &natural_width);
9292         }
9293
9294       return natural_width;
9295     }
9296   else
9297     return priv->allocation.x2 - priv->allocation.x1;
9298 }
9299
9300 /**
9301  * clutter_actor_get_height:
9302  * @self: A #ClutterActor
9303  *
9304  * Retrieves the height of a #ClutterActor.
9305  *
9306  * If the actor has a valid allocation, this function will return the
9307  * height of the allocated area given to the actor.
9308  *
9309  * If the actor does not have a valid allocation, this function will
9310  * return the actor's natural height, that is the preferred height of
9311  * the actor.
9312  *
9313  * If you care whether you get the preferred height or the height that
9314  * has been assigned to the actor, you should probably call a different
9315  * function like clutter_actor_get_allocation_box() to retrieve the
9316  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9317  * preferred height.
9318  *
9319  * If an actor has a fixed height, for instance a height that has been
9320  * assigned using clutter_actor_set_height(), the height returned will
9321  * be the same value.
9322  *
9323  * Return value: the height of the actor, in pixels
9324  */
9325 gfloat
9326 clutter_actor_get_height (ClutterActor *self)
9327 {
9328   ClutterActorPrivate *priv;
9329
9330   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9331
9332   priv = self->priv;
9333
9334   if (priv->needs_allocation)
9335     {
9336       gfloat natural_height = 0;
9337
9338       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9339         {
9340           gfloat natural_width = 0;
9341
9342           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9343           clutter_actor_get_preferred_height (self, natural_width,
9344                                               NULL, &natural_height);
9345         }
9346       else
9347         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9348
9349       return natural_height;
9350     }
9351   else
9352     return priv->allocation.y2 - priv->allocation.y1;
9353 }
9354
9355 /**
9356  * clutter_actor_set_width:
9357  * @self: A #ClutterActor
9358  * @width: Requested new width for the actor, in pixels, or -1
9359  *
9360  * Forces a width on an actor, causing the actor's preferred width
9361  * and height (if any) to be ignored.
9362  *
9363  * If @width is -1 the actor will use its preferred width request
9364  * instead of overriding it, i.e. you can "unset" the width with -1.
9365  *
9366  * This function sets both the minimum and natural size of the actor.
9367  *
9368  * since: 0.2
9369  */
9370 void
9371 clutter_actor_set_width (ClutterActor *self,
9372                          gfloat        width)
9373 {
9374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9375
9376   if (clutter_actor_get_easing_duration (self) != 0)
9377     {
9378       ClutterTransition *transition;
9379
9380       transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9381       if (transition == NULL)
9382         {
9383           float old_width = clutter_actor_get_width (self);
9384
9385           transition = _clutter_actor_create_transition (self,
9386                                                          obj_props[PROP_WIDTH],
9387                                                          old_width,
9388                                                          width);
9389           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9390         }
9391       else
9392         _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9393
9394       clutter_actor_queue_relayout (self);
9395     }
9396   else
9397     {
9398       g_object_freeze_notify (G_OBJECT (self));
9399
9400       clutter_actor_set_width_internal (self, width);
9401
9402       g_object_thaw_notify (G_OBJECT (self));
9403     }
9404 }
9405
9406 /**
9407  * clutter_actor_set_height:
9408  * @self: A #ClutterActor
9409  * @height: Requested new height for the actor, in pixels, or -1
9410  *
9411  * Forces a height on an actor, causing the actor's preferred width
9412  * and height (if any) to be ignored.
9413  *
9414  * If @height is -1 the actor will use its preferred height instead of
9415  * overriding it, i.e. you can "unset" the height with -1.
9416  *
9417  * This function sets both the minimum and natural size of the actor.
9418  *
9419  * since: 0.2
9420  */
9421 void
9422 clutter_actor_set_height (ClutterActor *self,
9423                           gfloat        height)
9424 {
9425   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9426
9427   if (clutter_actor_get_easing_duration (self) != 0)
9428     {
9429       ClutterTransition *transition;
9430
9431       transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9432       if (transition ==  NULL)
9433         {
9434           float old_height = clutter_actor_get_height (self);
9435
9436           transition = _clutter_actor_create_transition (self,
9437                                                          obj_props[PROP_HEIGHT],
9438                                                          old_height,
9439                                                          height);
9440           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9441         }
9442       else
9443         _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9444
9445       clutter_actor_queue_relayout (self);
9446     }
9447   else
9448     {
9449       g_object_freeze_notify (G_OBJECT (self));
9450
9451       clutter_actor_set_height_internal (self, height);
9452
9453       g_object_thaw_notify (G_OBJECT (self));
9454     }
9455 }
9456
9457 static inline void
9458 clutter_actor_set_x_internal (ClutterActor *self,
9459                               float         x)
9460 {
9461   ClutterActorPrivate *priv = self->priv;
9462   ClutterLayoutInfo *linfo;
9463   ClutterActorBox old = { 0, };
9464
9465   linfo = _clutter_actor_get_layout_info (self);
9466
9467   if (priv->position_set && linfo->fixed_x == x)
9468     return;
9469
9470   clutter_actor_store_old_geometry (self, &old);
9471
9472   linfo->fixed_x = x;
9473   clutter_actor_set_fixed_position_set (self, TRUE);
9474
9475   clutter_actor_notify_if_geometry_changed (self, &old);
9476
9477   clutter_actor_queue_relayout (self);
9478 }
9479
9480 static inline void
9481 clutter_actor_set_y_internal (ClutterActor *self,
9482                               float         y)
9483 {
9484   ClutterActorPrivate *priv = self->priv;
9485   ClutterLayoutInfo *linfo;
9486   ClutterActorBox old = { 0, };
9487
9488   linfo = _clutter_actor_get_layout_info (self);
9489
9490   if (priv->position_set && linfo->fixed_y == y)
9491     return;
9492
9493   clutter_actor_store_old_geometry (self, &old);
9494
9495   linfo->fixed_y = y;
9496   clutter_actor_set_fixed_position_set (self, TRUE);
9497
9498   clutter_actor_notify_if_geometry_changed (self, &old);
9499
9500   clutter_actor_queue_relayout (self);
9501 }
9502
9503 /**
9504  * clutter_actor_set_x:
9505  * @self: a #ClutterActor
9506  * @x: the actor's position on the X axis
9507  *
9508  * Sets the actor's X coordinate, relative to its parent, in pixels.
9509  *
9510  * Overrides any layout manager and forces a fixed position for
9511  * the actor.
9512  *
9513  * The #ClutterActor:x property is animatable.
9514  *
9515  * Since: 0.6
9516  */
9517 void
9518 clutter_actor_set_x (ClutterActor *self,
9519                      gfloat        x)
9520 {
9521   const ClutterLayoutInfo *linfo;
9522
9523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9524
9525   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9526
9527   if (clutter_actor_get_easing_duration (self) != 0)
9528     {
9529       ClutterTransition *transition;
9530
9531       transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9532       if (transition == NULL)
9533         {
9534           transition = _clutter_actor_create_transition (self,
9535                                                          obj_props[PROP_X],
9536                                                          linfo->fixed_x,
9537                                                          x);
9538
9539           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9540         }
9541       else
9542         _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9543
9544       clutter_actor_queue_relayout (self);
9545     }
9546   else
9547     clutter_actor_set_x_internal (self, x);
9548 }
9549
9550 /**
9551  * clutter_actor_set_y:
9552  * @self: a #ClutterActor
9553  * @y: the actor's position on the Y axis
9554  *
9555  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9556  *
9557  * Overrides any layout manager and forces a fixed position for
9558  * the actor.
9559  *
9560  * The #ClutterActor:y property is animatable.
9561  *
9562  * Since: 0.6
9563  */
9564 void
9565 clutter_actor_set_y (ClutterActor *self,
9566                      gfloat        y)
9567 {
9568   const ClutterLayoutInfo *linfo;
9569
9570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9571
9572   linfo = _clutter_actor_get_layout_info_or_defaults (self);
9573
9574   if (clutter_actor_get_easing_duration (self) != 0)
9575     {
9576       ClutterTransition *transition;
9577
9578       transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9579       if (transition == NULL)
9580         {
9581           transition = _clutter_actor_create_transition (self,
9582                                                          obj_props[PROP_Y],
9583                                                          linfo->fixed_y,
9584                                                          y);
9585
9586           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9587         }
9588       else
9589         _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9590
9591       clutter_actor_queue_relayout (self);
9592     }
9593   else
9594     clutter_actor_set_y_internal (self, y);
9595
9596   clutter_actor_queue_relayout (self);
9597 }
9598
9599 /**
9600  * clutter_actor_get_x:
9601  * @self: A #ClutterActor
9602  *
9603  * Retrieves the X coordinate of a #ClutterActor.
9604  *
9605  * This function tries to "do what you mean", by returning the
9606  * correct value depending on the actor's state.
9607  *
9608  * If the actor has a valid allocation, this function will return
9609  * the X coordinate of the origin of the allocation box.
9610  *
9611  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9612  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9613  * function will return that coordinate.
9614  *
9615  * If both the allocation and a fixed position are missing, this function
9616  * will return 0.
9617  *
9618  * Return value: the X coordinate, in pixels, ignoring any
9619  *   transformation (i.e. scaling, rotation)
9620  */
9621 gfloat
9622 clutter_actor_get_x (ClutterActor *self)
9623 {
9624   ClutterActorPrivate *priv;
9625
9626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9627
9628   priv = self->priv;
9629
9630   if (priv->needs_allocation)
9631     {
9632       if (priv->position_set)
9633         {
9634           const ClutterLayoutInfo *info;
9635
9636           info = _clutter_actor_get_layout_info_or_defaults (self);
9637
9638           return info->fixed_x;
9639         }
9640       else
9641         return 0;
9642     }
9643   else
9644     return priv->allocation.x1;
9645 }
9646
9647 /**
9648  * clutter_actor_get_y:
9649  * @self: A #ClutterActor
9650  *
9651  * Retrieves the Y coordinate of a #ClutterActor.
9652  *
9653  * This function tries to "do what you mean", by returning the
9654  * correct value depending on the actor's state.
9655  *
9656  * If the actor has a valid allocation, this function will return
9657  * the Y coordinate of the origin of the allocation box.
9658  *
9659  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9660  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9661  * function will return that coordinate.
9662  *
9663  * If both the allocation and a fixed position are missing, this function
9664  * will return 0.
9665  *
9666  * Return value: the Y coordinate, in pixels, ignoring any
9667  *   transformation (i.e. scaling, rotation)
9668  */
9669 gfloat
9670 clutter_actor_get_y (ClutterActor *self)
9671 {
9672   ClutterActorPrivate *priv;
9673
9674   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9675
9676   priv = self->priv;
9677
9678   if (priv->needs_allocation)
9679     {
9680       if (priv->position_set)
9681         {
9682           const ClutterLayoutInfo *info;
9683
9684           info = _clutter_actor_get_layout_info_or_defaults (self);
9685
9686           return info->fixed_y;
9687         }
9688       else
9689         return 0;
9690     }
9691   else
9692     return priv->allocation.y1;
9693 }
9694
9695 /**
9696  * clutter_actor_set_scale:
9697  * @self: A #ClutterActor
9698  * @scale_x: double factor to scale actor by horizontally.
9699  * @scale_y: double factor to scale actor by vertically.
9700  *
9701  * Scales an actor with the given factors. The scaling is relative to
9702  * the scale center and the anchor point. The scale center is
9703  * unchanged by this function and defaults to 0,0.
9704  *
9705  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9706  * animatable.
9707  *
9708  * Since: 0.2
9709  */
9710 void
9711 clutter_actor_set_scale (ClutterActor *self,
9712                          gdouble       scale_x,
9713                          gdouble       scale_y)
9714 {
9715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9716
9717   g_object_freeze_notify (G_OBJECT (self));
9718
9719   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9720   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9721
9722   g_object_thaw_notify (G_OBJECT (self));
9723 }
9724
9725 /**
9726  * clutter_actor_set_scale_full:
9727  * @self: A #ClutterActor
9728  * @scale_x: double factor to scale actor by horizontally.
9729  * @scale_y: double factor to scale actor by vertically.
9730  * @center_x: X coordinate of the center of the scale.
9731  * @center_y: Y coordinate of the center of the scale
9732  *
9733  * Scales an actor with the given factors around the given center
9734  * point. The center point is specified in pixels relative to the
9735  * anchor point (usually the top left corner of the actor).
9736  *
9737  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9738  * are animatable.
9739  *
9740  * Since: 1.0
9741  */
9742 void
9743 clutter_actor_set_scale_full (ClutterActor *self,
9744                               gdouble       scale_x,
9745                               gdouble       scale_y,
9746                               gfloat        center_x,
9747                               gfloat        center_y)
9748 {
9749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9750
9751   g_object_freeze_notify (G_OBJECT (self));
9752
9753   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9754   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9755   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9756   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9757
9758   g_object_thaw_notify (G_OBJECT (self));
9759 }
9760
9761 /**
9762  * clutter_actor_set_scale_with_gravity:
9763  * @self: A #ClutterActor
9764  * @scale_x: double factor to scale actor by horizontally.
9765  * @scale_y: double factor to scale actor by vertically.
9766  * @gravity: the location of the scale center expressed as a compass
9767  * direction.
9768  *
9769  * Scales an actor with the given factors around the given
9770  * center point. The center point is specified as one of the compass
9771  * directions in #ClutterGravity. For example, setting it to north
9772  * will cause the top of the actor to remain unchanged and the rest of
9773  * the actor to expand left, right and downwards.
9774  *
9775  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9776  * animatable.
9777  *
9778  * Since: 1.0
9779  */
9780 void
9781 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9782                                       gdouble         scale_x,
9783                                       gdouble         scale_y,
9784                                       ClutterGravity  gravity)
9785 {
9786   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9787
9788   g_object_freeze_notify (G_OBJECT (self));
9789
9790   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9791   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9792   clutter_actor_set_scale_gravity (self, gravity);
9793
9794   g_object_thaw_notify (G_OBJECT (self));
9795 }
9796
9797 /**
9798  * clutter_actor_get_scale:
9799  * @self: A #ClutterActor
9800  * @scale_x: (out) (allow-none): Location to store horizonal
9801  *   scale factor, or %NULL.
9802  * @scale_y: (out) (allow-none): Location to store vertical
9803  *   scale factor, or %NULL.
9804  *
9805  * Retrieves an actors scale factors.
9806  *
9807  * Since: 0.2
9808  */
9809 void
9810 clutter_actor_get_scale (ClutterActor *self,
9811                          gdouble      *scale_x,
9812                          gdouble      *scale_y)
9813 {
9814   const ClutterTransformInfo *info;
9815
9816   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9817
9818   info = _clutter_actor_get_transform_info_or_defaults (self);
9819
9820   if (scale_x)
9821     *scale_x = info->scale_x;
9822
9823   if (scale_y)
9824     *scale_y = info->scale_y;
9825 }
9826
9827 /**
9828  * clutter_actor_get_scale_center:
9829  * @self: A #ClutterActor
9830  * @center_x: (out) (allow-none): Location to store the X position
9831  *   of the scale center, or %NULL.
9832  * @center_y: (out) (allow-none): Location to store the Y position
9833  *   of the scale center, or %NULL.
9834  *
9835  * Retrieves the scale center coordinate in pixels relative to the top
9836  * left corner of the actor. If the scale center was specified using a
9837  * #ClutterGravity this will calculate the pixel offset using the
9838  * current size of the actor.
9839  *
9840  * Since: 1.0
9841  */
9842 void
9843 clutter_actor_get_scale_center (ClutterActor *self,
9844                                 gfloat       *center_x,
9845                                 gfloat       *center_y)
9846 {
9847   const ClutterTransformInfo *info;
9848
9849   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9850
9851   info = _clutter_actor_get_transform_info_or_defaults (self);
9852
9853   clutter_anchor_coord_get_units (self, &info->scale_center,
9854                                   center_x,
9855                                   center_y,
9856                                   NULL);
9857 }
9858
9859 /**
9860  * clutter_actor_get_scale_gravity:
9861  * @self: A #ClutterActor
9862  *
9863  * Retrieves the scale center as a compass direction. If the scale
9864  * center was specified in pixels or units this will return
9865  * %CLUTTER_GRAVITY_NONE.
9866  *
9867  * Return value: the scale gravity
9868  *
9869  * Since: 1.0
9870  */
9871 ClutterGravity
9872 clutter_actor_get_scale_gravity (ClutterActor *self)
9873 {
9874   const ClutterTransformInfo *info;
9875
9876   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9877
9878   info = _clutter_actor_get_transform_info_or_defaults (self);
9879
9880   return clutter_anchor_coord_get_gravity (&info->scale_center);
9881 }
9882
9883 static inline void
9884 clutter_actor_set_opacity_internal (ClutterActor *self,
9885                                     guint8        opacity)
9886 {
9887   ClutterActorPrivate *priv = self->priv;
9888
9889   if (priv->opacity != opacity)
9890     {
9891       priv->opacity = opacity;
9892
9893       /* Queue a redraw from the flatten effect so that it can use
9894          its cached image if available instead of having to redraw the
9895          actual actor. If it doesn't end up using the FBO then the
9896          effect is still able to continue the paint anyway. If there
9897          is no flatten effect yet then this is equivalent to queueing
9898          a full redraw */
9899       _clutter_actor_queue_redraw_full (self,
9900                                         0, /* flags */
9901                                         NULL, /* clip */
9902                                         priv->flatten_effect);
9903
9904       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9905     }
9906 }
9907
9908 /**
9909  * clutter_actor_set_opacity:
9910  * @self: A #ClutterActor
9911  * @opacity: New opacity value for the actor.
9912  *
9913  * Sets the actor's opacity, with zero being completely transparent and
9914  * 255 (0xff) being fully opaque.
9915  *
9916  * The #ClutterActor:opacity property is animatable.
9917  */
9918 void
9919 clutter_actor_set_opacity (ClutterActor *self,
9920                            guint8        opacity)
9921 {
9922   ClutterActorPrivate *priv;
9923
9924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9925
9926   priv = self->priv;
9927
9928   if (clutter_actor_get_easing_duration (self) != 0)
9929     {
9930       ClutterTransition *transition;
9931
9932       transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9933       if (transition == NULL)
9934         {
9935           transition = _clutter_actor_create_transition (self,
9936                                                          obj_props[PROP_OPACITY],
9937                                                          priv->opacity,
9938                                                          opacity);
9939           clutter_timeline_start (CLUTTER_TIMELINE (transition));
9940         }
9941       else
9942         _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9943
9944       clutter_actor_queue_redraw (self);
9945     }
9946   else
9947     clutter_actor_set_opacity_internal (self, opacity);
9948 }
9949
9950 /*
9951  * clutter_actor_get_paint_opacity_internal:
9952  * @self: a #ClutterActor
9953  *
9954  * Retrieves the absolute opacity of the actor, as it appears on the stage
9955  *
9956  * This function does not do type checks
9957  *
9958  * Return value: the absolute opacity of the actor
9959  */
9960 static guint8
9961 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9962 {
9963   ClutterActorPrivate *priv = self->priv;
9964   ClutterActor *parent;
9965
9966   /* override the top-level opacity to always be 255; even in
9967    * case of ClutterStage:use-alpha being TRUE we want the rest
9968    * of the scene to be painted
9969    */
9970   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9971     return 255;
9972
9973   if (priv->opacity_override >= 0)
9974     return priv->opacity_override;
9975
9976   parent = priv->parent;
9977
9978   /* Factor in the actual actors opacity with parents */
9979   if (parent != NULL)
9980     {
9981       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9982
9983       if (opacity != 0xff)
9984         return (opacity * priv->opacity) / 0xff;
9985     }
9986
9987   return priv->opacity;
9988
9989 }
9990
9991 /**
9992  * clutter_actor_get_paint_opacity:
9993  * @self: A #ClutterActor
9994  *
9995  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9996  *
9997  * This function traverses the hierarchy chain and composites the opacity of
9998  * the actor with that of its parents.
9999  *
10000  * This function is intended for subclasses to use in the paint virtual
10001  * function, to paint themselves with the correct opacity.
10002  *
10003  * Return value: The actor opacity value.
10004  *
10005  * Since: 0.8
10006  */
10007 guint8
10008 clutter_actor_get_paint_opacity (ClutterActor *self)
10009 {
10010   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10011
10012   return clutter_actor_get_paint_opacity_internal (self);
10013 }
10014
10015 /**
10016  * clutter_actor_get_opacity:
10017  * @self: a #ClutterActor
10018  *
10019  * Retrieves the opacity value of an actor, as set by
10020  * clutter_actor_set_opacity().
10021  *
10022  * For retrieving the absolute opacity of the actor inside a paint
10023  * virtual function, see clutter_actor_get_paint_opacity().
10024  *
10025  * Return value: the opacity of the actor
10026  */
10027 guint8
10028 clutter_actor_get_opacity (ClutterActor *self)
10029 {
10030   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10031
10032   return self->priv->opacity;
10033 }
10034
10035 /**
10036  * clutter_actor_set_offscreen_redirect:
10037  * @self: A #ClutterActor
10038  * @redirect: New offscreen redirect flags for the actor.
10039  *
10040  * Defines the circumstances where the actor should be redirected into
10041  * an offscreen image. The offscreen image is used to flatten the
10042  * actor into a single image while painting for two main reasons.
10043  * Firstly, when the actor is painted a second time without any of its
10044  * contents changing it can simply repaint the cached image without
10045  * descending further down the actor hierarchy. Secondly, it will make
10046  * the opacity look correct even if there are overlapping primitives
10047  * in the actor.
10048  *
10049  * Caching the actor could in some cases be a performance win and in
10050  * some cases be a performance lose so it is important to determine
10051  * which value is right for an actor before modifying this value. For
10052  * example, there is never any reason to flatten an actor that is just
10053  * a single texture (such as a #ClutterTexture) because it is
10054  * effectively already cached in an image so the offscreen would be
10055  * redundant. Also if the actor contains primitives that are far apart
10056  * with a large transparent area in the middle (such as a large
10057  * CluterGroup with a small actor in the top left and a small actor in
10058  * the bottom right) then the cached image will contain the entire
10059  * image of the large area and the paint will waste time blending all
10060  * of the transparent pixels in the middle.
10061  *
10062  * The default method of implementing opacity on a container simply
10063  * forwards on the opacity to all of the children. If the children are
10064  * overlapping then it will appear as if they are two separate glassy
10065  * objects and there will be a break in the color where they
10066  * overlap. By redirecting to an offscreen buffer it will be as if the
10067  * two opaque objects are combined into one and then made transparent
10068  * which is usually what is expected.
10069  *
10070  * The image below demonstrates the difference between redirecting and
10071  * not. The image shows two Clutter groups, each containing a red and
10072  * a green rectangle which overlap. The opacity on the group is set to
10073  * 128 (which is 50%). When the offscreen redirect is not used, the
10074  * red rectangle can be seen through the blue rectangle as if the two
10075  * rectangles were separately transparent. When the redirect is used
10076  * the group as a whole is transparent instead so the red rectangle is
10077  * not visible where they overlap.
10078  *
10079  * <figure id="offscreen-redirect">
10080  *   <title>Sample of using an offscreen redirect for transparency</title>
10081  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10082  * </figure>
10083  *
10084  * The default value for this property is 0, so we effectively will
10085  * never redirect an actor offscreen by default. This means that there
10086  * are times that transparent actors may look glassy as described
10087  * above. The reason this is the default is because there is a
10088  * performance trade off between quality and performance here. In many
10089  * cases the default form of glassy opacity looks good enough, but if
10090  * it's not you will need to set the
10091  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10092  * redirection for opacity.
10093  *
10094  * Custom actors that don't contain any overlapping primitives are
10095  * recommended to override the has_overlaps() virtual to return %FALSE
10096  * for maximum efficiency.
10097  *
10098  * Since: 1.8
10099  */
10100 void
10101 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10102                                       ClutterOffscreenRedirect redirect)
10103 {
10104   ClutterActorPrivate *priv;
10105
10106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10107
10108   priv = self->priv;
10109
10110   if (priv->offscreen_redirect != redirect)
10111     {
10112       priv->offscreen_redirect = redirect;
10113
10114       /* Queue a redraw from the effect so that it can use its cached
10115          image if available instead of having to redraw the actual
10116          actor. If it doesn't end up using the FBO then the effect is
10117          still able to continue the paint anyway. If there is no
10118          effect then this is equivalent to queuing a full redraw */
10119       _clutter_actor_queue_redraw_full (self,
10120                                         0, /* flags */
10121                                         NULL, /* clip */
10122                                         priv->flatten_effect);
10123
10124       g_object_notify_by_pspec (G_OBJECT (self),
10125                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10126     }
10127 }
10128
10129 /**
10130  * clutter_actor_get_offscreen_redirect:
10131  * @self: a #ClutterActor
10132  *
10133  * Retrieves whether to redirect the actor to an offscreen buffer, as
10134  * set by clutter_actor_set_offscreen_redirect().
10135  *
10136  * Return value: the value of the offscreen-redirect property of the actor
10137  *
10138  * Since: 1.8
10139  */
10140 ClutterOffscreenRedirect
10141 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10142 {
10143   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10144
10145   return self->priv->offscreen_redirect;
10146 }
10147
10148 /**
10149  * clutter_actor_set_name:
10150  * @self: A #ClutterActor
10151  * @name: Textual tag to apply to actor
10152  *
10153  * Sets the given name to @self. The name can be used to identify
10154  * a #ClutterActor.
10155  */
10156 void
10157 clutter_actor_set_name (ClutterActor *self,
10158                         const gchar  *name)
10159 {
10160   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10161
10162   g_free (self->priv->name);
10163   self->priv->name = g_strdup (name);
10164
10165   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10166 }
10167
10168 /**
10169  * clutter_actor_get_name:
10170  * @self: A #ClutterActor
10171  *
10172  * Retrieves the name of @self.
10173  *
10174  * Return value: the name of the actor, or %NULL. The returned string is
10175  *   owned by the actor and should not be modified or freed.
10176  */
10177 const gchar *
10178 clutter_actor_get_name (ClutterActor *self)
10179 {
10180   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10181
10182   return self->priv->name;
10183 }
10184
10185 /**
10186  * clutter_actor_get_gid:
10187  * @self: A #ClutterActor
10188  *
10189  * Retrieves the unique id for @self.
10190  *
10191  * Return value: Globally unique value for this object instance.
10192  *
10193  * Since: 0.6
10194  *
10195  * Deprecated: 1.8: The id is not used any longer.
10196  */
10197 guint32
10198 clutter_actor_get_gid (ClutterActor *self)
10199 {
10200   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10201
10202   return self->priv->id;
10203 }
10204
10205 static inline void
10206 clutter_actor_set_depth_internal (ClutterActor *self,
10207                                   float         depth)
10208 {
10209   ClutterTransformInfo *info;
10210
10211   info = _clutter_actor_get_transform_info (self);
10212
10213   if (info->depth != depth)
10214     {
10215       /* Sets Z value - XXX 2.0: should we invert? */
10216       info->depth = depth;
10217
10218       self->priv->transform_valid = FALSE;
10219
10220       /* FIXME - remove this crap; sadly, there are still containers
10221        * in Clutter that depend on this utter brain damage
10222        */
10223       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10224
10225       clutter_actor_queue_redraw (self);
10226
10227       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10228     }
10229 }
10230
10231 /**
10232  * clutter_actor_set_depth:
10233  * @self: a #ClutterActor
10234  * @depth: Z co-ord
10235  *
10236  * Sets the Z coordinate of @self to @depth.
10237  *
10238  * The unit used by @depth is dependant on the perspective setup. See
10239  * also clutter_stage_set_perspective().
10240  */
10241 void
10242 clutter_actor_set_depth (ClutterActor *self,
10243                          gfloat        depth)
10244 {
10245   const ClutterTransformInfo *tinfo;
10246
10247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10248
10249   tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10250
10251   if (clutter_actor_get_easing_duration (self) != 0)
10252     {
10253       ClutterTransition *transition;
10254
10255       transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10256       if (transition == NULL)
10257         {
10258           transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10259                                                          tinfo->depth,
10260                                                          depth);
10261           clutter_timeline_start (CLUTTER_TIMELINE (transition));
10262         }
10263       else
10264         _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10265
10266       clutter_actor_queue_redraw (self);
10267     }
10268   else
10269     clutter_actor_set_depth_internal (self, depth);
10270 }
10271
10272 /**
10273  * clutter_actor_get_depth:
10274  * @self: a #ClutterActor
10275  *
10276  * Retrieves the depth of @self.
10277  *
10278  * Return value: the depth of the actor
10279  */
10280 gfloat
10281 clutter_actor_get_depth (ClutterActor *self)
10282 {
10283   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10284
10285   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10286 }
10287
10288 /**
10289  * clutter_actor_set_rotation:
10290  * @self: a #ClutterActor
10291  * @axis: the axis of rotation
10292  * @angle: the angle of rotation
10293  * @x: X coordinate of the rotation center
10294  * @y: Y coordinate of the rotation center
10295  * @z: Z coordinate of the rotation center
10296  *
10297  * Sets the rotation angle of @self around the given axis.
10298  *
10299  * The rotation center coordinates used depend on the value of @axis:
10300  * <itemizedlist>
10301  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10302  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10303  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10304  * </itemizedlist>
10305  *
10306  * The rotation coordinates are relative to the anchor point of the
10307  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10308  * point is set, the upper left corner is assumed as the origin.
10309  *
10310  * Since: 0.8
10311  */
10312 void
10313 clutter_actor_set_rotation (ClutterActor      *self,
10314                             ClutterRotateAxis  axis,
10315                             gdouble            angle,
10316                             gfloat             x,
10317                             gfloat             y,
10318                             gfloat             z)
10319 {
10320   ClutterVertex v;
10321
10322   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10323
10324   v.x = x;
10325   v.y = y;
10326   v.z = z;
10327
10328   g_object_freeze_notify (G_OBJECT (self));
10329
10330   clutter_actor_set_rotation_angle (self, axis, angle);
10331   clutter_actor_set_rotation_center_internal (self, axis, &v);
10332
10333   g_object_thaw_notify (G_OBJECT (self));
10334 }
10335
10336 /**
10337  * clutter_actor_set_z_rotation_from_gravity:
10338  * @self: a #ClutterActor
10339  * @angle: the angle of rotation
10340  * @gravity: the center point of the rotation
10341  *
10342  * Sets the rotation angle of @self around the Z axis using the center
10343  * point specified as a compass point. For example to rotate such that
10344  * the center of the actor remains static you can use
10345  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10346  * will move accordingly.
10347  *
10348  * Since: 1.0
10349  */
10350 void
10351 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10352                                            gdouble         angle,
10353                                            ClutterGravity  gravity)
10354 {
10355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10356
10357   if (gravity == CLUTTER_GRAVITY_NONE)
10358     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10359   else
10360     {
10361       GObject *obj = G_OBJECT (self);
10362       ClutterTransformInfo *info;
10363
10364       info = _clutter_actor_get_transform_info (self);
10365
10366       g_object_freeze_notify (obj);
10367
10368       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10369
10370       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10371       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10372       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10373
10374       g_object_thaw_notify (obj);
10375     }
10376 }
10377
10378 /**
10379  * clutter_actor_get_rotation:
10380  * @self: a #ClutterActor
10381  * @axis: the axis of rotation
10382  * @x: (out): return value for the X coordinate of the center of rotation
10383  * @y: (out): return value for the Y coordinate of the center of rotation
10384  * @z: (out): return value for the Z coordinate of the center of rotation
10385  *
10386  * Retrieves the angle and center of rotation on the given axis,
10387  * set using clutter_actor_set_rotation().
10388  *
10389  * Return value: the angle of rotation
10390  *
10391  * Since: 0.8
10392  */
10393 gdouble
10394 clutter_actor_get_rotation (ClutterActor      *self,
10395                             ClutterRotateAxis  axis,
10396                             gfloat            *x,
10397                             gfloat            *y,
10398                             gfloat            *z)
10399 {
10400   const ClutterTransformInfo *info;
10401   const AnchorCoord *anchor_coord;
10402   gdouble retval = 0;
10403
10404   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10405
10406   info = _clutter_actor_get_transform_info_or_defaults (self);
10407
10408   switch (axis)
10409     {
10410     case CLUTTER_X_AXIS:
10411       anchor_coord = &info->rx_center;
10412       retval = info->rx_angle;
10413       break;
10414
10415     case CLUTTER_Y_AXIS:
10416       anchor_coord = &info->ry_center;
10417       retval = info->ry_angle;
10418       break;
10419
10420     case CLUTTER_Z_AXIS:
10421       anchor_coord = &info->rz_center;
10422       retval = info->rz_angle;
10423       break;
10424
10425     default:
10426       anchor_coord = NULL;
10427       retval = 0.0;
10428       break;
10429     }
10430
10431   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10432
10433   return retval;
10434 }
10435
10436 /**
10437  * clutter_actor_get_z_rotation_gravity:
10438  * @self: A #ClutterActor
10439  *
10440  * Retrieves the center for the rotation around the Z axis as a
10441  * compass direction. If the center was specified in pixels or units
10442  * this will return %CLUTTER_GRAVITY_NONE.
10443  *
10444  * Return value: the Z rotation center
10445  *
10446  * Since: 1.0
10447  */
10448 ClutterGravity
10449 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10450 {
10451   const ClutterTransformInfo *info;
10452
10453   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10454
10455   info = _clutter_actor_get_transform_info_or_defaults (self);
10456
10457   return clutter_anchor_coord_get_gravity (&info->rz_center);
10458 }
10459
10460 /**
10461  * clutter_actor_set_clip:
10462  * @self: A #ClutterActor
10463  * @xoff: X offset of the clip rectangle
10464  * @yoff: Y offset of the clip rectangle
10465  * @width: Width of the clip rectangle
10466  * @height: Height of the clip rectangle
10467  *
10468  * Sets clip area for @self. The clip area is always computed from the
10469  * upper left corner of the actor, even if the anchor point is set
10470  * otherwise.
10471  *
10472  * Since: 0.6
10473  */
10474 void
10475 clutter_actor_set_clip (ClutterActor *self,
10476                         gfloat        xoff,
10477                         gfloat        yoff,
10478                         gfloat        width,
10479                         gfloat        height)
10480 {
10481   ClutterActorPrivate *priv;
10482
10483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10484
10485   priv = self->priv;
10486
10487   if (priv->has_clip &&
10488       priv->clip.x == xoff &&
10489       priv->clip.y == yoff &&
10490       priv->clip.width == width &&
10491       priv->clip.height == height)
10492     return;
10493
10494   priv->clip.x = xoff;
10495   priv->clip.y = yoff;
10496   priv->clip.width = width;
10497   priv->clip.height = height;
10498
10499   priv->has_clip = TRUE;
10500
10501   clutter_actor_queue_redraw (self);
10502
10503   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10504   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10505 }
10506
10507 /**
10508  * clutter_actor_remove_clip:
10509  * @self: A #ClutterActor
10510  *
10511  * Removes clip area from @self.
10512  */
10513 void
10514 clutter_actor_remove_clip (ClutterActor *self)
10515 {
10516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10517
10518   if (!self->priv->has_clip)
10519     return;
10520
10521   self->priv->has_clip = FALSE;
10522
10523   clutter_actor_queue_redraw (self);
10524
10525   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10526 }
10527
10528 /**
10529  * clutter_actor_has_clip:
10530  * @self: a #ClutterActor
10531  *
10532  * Determines whether the actor has a clip area set or not.
10533  *
10534  * Return value: %TRUE if the actor has a clip area set.
10535  *
10536  * Since: 0.1.1
10537  */
10538 gboolean
10539 clutter_actor_has_clip (ClutterActor *self)
10540 {
10541   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10542
10543   return self->priv->has_clip;
10544 }
10545
10546 /**
10547  * clutter_actor_get_clip:
10548  * @self: a #ClutterActor
10549  * @xoff: (out) (allow-none): return location for the X offset of
10550  *   the clip rectangle, or %NULL
10551  * @yoff: (out) (allow-none): return location for the Y offset of
10552  *   the clip rectangle, or %NULL
10553  * @width: (out) (allow-none): return location for the width of
10554  *   the clip rectangle, or %NULL
10555  * @height: (out) (allow-none): return location for the height of
10556  *   the clip rectangle, or %NULL
10557  *
10558  * Gets the clip area for @self, if any is set
10559  *
10560  * Since: 0.6
10561  */
10562 void
10563 clutter_actor_get_clip (ClutterActor *self,
10564                         gfloat       *xoff,
10565                         gfloat       *yoff,
10566                         gfloat       *width,
10567                         gfloat       *height)
10568 {
10569   ClutterActorPrivate *priv;
10570
10571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10572
10573   priv = self->priv;
10574
10575   if (!priv->has_clip)
10576     return;
10577
10578   if (xoff != NULL)
10579     *xoff = priv->clip.x;
10580
10581   if (yoff != NULL)
10582     *yoff = priv->clip.y;
10583
10584   if (width != NULL)
10585     *width = priv->clip.width;
10586
10587   if (height != NULL)
10588     *height = priv->clip.height;
10589 }
10590
10591 /**
10592  * clutter_actor_get_children:
10593  * @self: a #ClutterActor
10594  *
10595  * Retrieves the list of children of @self.
10596  *
10597  * Return value: (transfer container) (element-type ClutterActor): A newly
10598  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10599  *   done.
10600  *
10601  * Since: 1.10
10602  */
10603 GList *
10604 clutter_actor_get_children (ClutterActor *self)
10605 {
10606   ClutterActor *iter;
10607   GList *res;
10608
10609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10610
10611   /* we walk the list backward so that we can use prepend(),
10612    * which is O(1)
10613    */
10614   for (iter = self->priv->last_child, res = NULL;
10615        iter != NULL;
10616        iter = iter->priv->prev_sibling)
10617     {
10618       res = g_list_prepend (res, iter);
10619     }
10620
10621   return res;
10622 }
10623
10624 /*< private >
10625  * insert_child_at_depth:
10626  * @self: a #ClutterActor
10627  * @child: a #ClutterActor
10628  *
10629  * Inserts @child inside the list of children held by @self, using
10630  * the depth as the insertion criteria.
10631  *
10632  * This sadly makes the insertion not O(1), but we can keep the
10633  * list sorted so that the painters algorithm we use for painting
10634  * the children will work correctly.
10635  */
10636 static void
10637 insert_child_at_depth (ClutterActor *self,
10638                        ClutterActor *child,
10639                        gpointer      dummy G_GNUC_UNUSED)
10640 {
10641   ClutterActor *iter;
10642   float child_depth;
10643
10644   child->priv->parent = self;
10645
10646   child_depth =
10647     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10648
10649   /* special-case the first child */
10650   if (self->priv->n_children == 0)
10651     {
10652       self->priv->first_child = child;
10653       self->priv->last_child = child;
10654
10655       child->priv->next_sibling = NULL;
10656       child->priv->prev_sibling = NULL;
10657
10658       return;
10659     }
10660
10661   /* Find the right place to insert the child so that it will still be
10662      sorted and the child will be after all of the actors at the same
10663      dept */
10664   for (iter = self->priv->first_child;
10665        iter != NULL;
10666        iter = iter->priv->next_sibling)
10667     {
10668       float iter_depth;
10669
10670       iter_depth =
10671         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10672
10673       if (iter_depth > child_depth)
10674         break;
10675     }
10676
10677   if (iter != NULL)
10678     {
10679       ClutterActor *tmp = iter->priv->prev_sibling;
10680
10681       if (tmp != NULL)
10682         tmp->priv->next_sibling = child;
10683
10684       /* Insert the node before the found one */
10685       child->priv->prev_sibling = iter->priv->prev_sibling;
10686       child->priv->next_sibling = iter;
10687       iter->priv->prev_sibling = child;
10688     }
10689   else
10690     {
10691       ClutterActor *tmp = self->priv->last_child;
10692
10693       if (tmp != NULL)
10694         tmp->priv->next_sibling = child;
10695
10696       /* insert the node at the end of the list */
10697       child->priv->prev_sibling = self->priv->last_child;
10698       child->priv->next_sibling = NULL;
10699     }
10700
10701   if (child->priv->prev_sibling == NULL)
10702     self->priv->first_child = child;
10703
10704   if (child->priv->next_sibling == NULL)
10705     self->priv->last_child = child;
10706 }
10707
10708 static void
10709 insert_child_at_index (ClutterActor *self,
10710                        ClutterActor *child,
10711                        gpointer      data_)
10712 {
10713   gint index_ = GPOINTER_TO_INT (data_);
10714
10715   child->priv->parent = self;
10716
10717   if (index_ == 0)
10718     {
10719       ClutterActor *tmp = self->priv->first_child;
10720
10721       if (tmp != NULL)
10722         tmp->priv->prev_sibling = child;
10723
10724       child->priv->prev_sibling = NULL;
10725       child->priv->next_sibling = tmp;
10726     }
10727   else if (index_ < 0 || index_ >= self->priv->n_children)
10728     {
10729       ClutterActor *tmp = self->priv->last_child;
10730
10731       if (tmp != NULL)
10732         tmp->priv->next_sibling = child;
10733
10734       child->priv->prev_sibling = tmp;
10735       child->priv->next_sibling = NULL;
10736     }
10737   else
10738     {
10739       ClutterActor *iter;
10740       int i;
10741
10742       for (iter = self->priv->first_child, i = 0;
10743            iter != NULL;
10744            iter = iter->priv->next_sibling, i += 1)
10745         {
10746           if (index_ == i)
10747             {
10748               ClutterActor *tmp = iter->priv->prev_sibling;
10749
10750               child->priv->prev_sibling = tmp;
10751               child->priv->next_sibling = iter;
10752
10753               iter->priv->prev_sibling = child;
10754
10755               if (tmp != NULL)
10756                 tmp->priv->next_sibling = child;
10757
10758               break;
10759             }
10760         }
10761     }
10762
10763   if (child->priv->prev_sibling == NULL)
10764     self->priv->first_child = child;
10765
10766   if (child->priv->next_sibling == NULL)
10767     self->priv->last_child = child;
10768 }
10769
10770 static void
10771 insert_child_above (ClutterActor *self,
10772                     ClutterActor *child,
10773                     gpointer      data)
10774 {
10775   ClutterActor *sibling = data;
10776
10777   child->priv->parent = self;
10778
10779   if (sibling == NULL)
10780     sibling = self->priv->last_child;
10781
10782   child->priv->prev_sibling = sibling;
10783
10784   if (sibling != NULL)
10785     {
10786       ClutterActor *tmp = sibling->priv->next_sibling;
10787
10788       child->priv->next_sibling = tmp;
10789
10790       if (tmp != NULL)
10791         tmp->priv->prev_sibling = child;
10792
10793       sibling->priv->next_sibling = child;
10794     }
10795   else
10796     child->priv->next_sibling = NULL;
10797
10798   if (child->priv->prev_sibling == NULL)
10799     self->priv->first_child = child;
10800
10801   if (child->priv->next_sibling == NULL)
10802     self->priv->last_child = child;
10803 }
10804
10805 static void
10806 insert_child_below (ClutterActor *self,
10807                     ClutterActor *child,
10808                     gpointer      data)
10809 {
10810   ClutterActor *sibling = data;
10811
10812   child->priv->parent = self;
10813
10814   if (sibling == NULL)
10815     sibling = self->priv->first_child;
10816
10817   child->priv->next_sibling = sibling;
10818
10819   if (sibling != NULL)
10820     {
10821       ClutterActor *tmp = sibling->priv->prev_sibling;
10822
10823       child->priv->prev_sibling = tmp;
10824
10825       if (tmp != NULL)
10826         tmp->priv->next_sibling = child;
10827
10828       sibling->priv->prev_sibling = child;
10829     }
10830   else
10831     child->priv->prev_sibling = NULL;
10832
10833   if (child->priv->prev_sibling == NULL)
10834     self->priv->first_child = child;
10835
10836   if (child->priv->next_sibling == NULL)
10837     self->priv->last_child = child;
10838 }
10839
10840 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10841                                            ClutterActor *child,
10842                                            gpointer      data);
10843
10844 typedef enum {
10845   ADD_CHILD_CREATE_META       = 1 << 0,
10846   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10847   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10848   ADD_CHILD_CHECK_STATE       = 1 << 3,
10849   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10850
10851   /* default flags for public API */
10852   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10853                                ADD_CHILD_EMIT_PARENT_SET |
10854                                ADD_CHILD_EMIT_ACTOR_ADDED |
10855                                ADD_CHILD_CHECK_STATE |
10856                                ADD_CHILD_NOTIFY_FIRST_LAST,
10857
10858   /* flags for legacy/deprecated API */
10859   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10860                                ADD_CHILD_CHECK_STATE |
10861                                ADD_CHILD_NOTIFY_FIRST_LAST
10862 } ClutterActorAddChildFlags;
10863
10864 /*< private >
10865  * clutter_actor_add_child_internal:
10866  * @self: a #ClutterActor
10867  * @child: a #ClutterActor
10868  * @flags: control flags for actions
10869  * @add_func: delegate function
10870  * @data: (closure): data to pass to @add_func
10871  *
10872  * Adds @child to the list of children of @self.
10873  *
10874  * The actual insertion inside the list is delegated to @add_func: this
10875  * function will just set up the state, perform basic checks, and emit
10876  * signals.
10877  *
10878  * The @flags argument is used to perform additional operations.
10879  */
10880 static inline void
10881 clutter_actor_add_child_internal (ClutterActor              *self,
10882                                   ClutterActor              *child,
10883                                   ClutterActorAddChildFlags  flags,
10884                                   ClutterActorAddChildFunc   add_func,
10885                                   gpointer                   data)
10886 {
10887   ClutterTextDirection text_dir;
10888   gboolean create_meta;
10889   gboolean emit_parent_set, emit_actor_added;
10890   gboolean check_state;
10891   gboolean notify_first_last;
10892   ClutterActor *old_first_child, *old_last_child;
10893
10894   if (child->priv->parent != NULL)
10895     {
10896       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10897                  "use clutter_actor_remove_child() first.",
10898                  _clutter_actor_get_debug_name (child),
10899                  _clutter_actor_get_debug_name (child->priv->parent));
10900       return;
10901     }
10902
10903   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10904     {
10905       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10906                  "a child of another actor.",
10907                  _clutter_actor_get_debug_name (child));
10908       return;
10909     }
10910
10911 #if 0
10912   /* XXX - this check disallows calling methods that change the stacking
10913    * order within the destruction sequence, by triggering a critical
10914    * warning first, and leaving the actor in an undefined state, which
10915    * then ends up being caught by an assertion.
10916    *
10917    * the reproducible sequence is:
10918    *
10919    *   - actor gets destroyed;
10920    *   - another actor, linked to the first, will try to change the
10921    *     stacking order of the first actor;
10922    *   - changing the stacking order is a composite operation composed
10923    *     by the following steps:
10924    *     1. ref() the child;
10925    *     2. remove_child_internal(), which removes the reference;
10926    *     3. add_child_internal(), which adds a reference;
10927    *   - the state of the actor is not changed between (2) and (3), as
10928    *     it could be an expensive recomputation;
10929    *   - if (3) bails out, then the actor is in an undefined state, but
10930    *     still alive;
10931    *   - the destruction sequence terminates, but the actor is unparented
10932    *     while its state indicates being parented instead.
10933    *   - assertion failure.
10934    *
10935    * the obvious fix would be to decompose each set_child_*_sibling()
10936    * method into proper remove_child()/add_child(), with state validation;
10937    * this may cause excessive work, though, and trigger a cascade of other
10938    * bugs in code that assumes that a change in the stacking order is an
10939    * atomic operation.
10940    *
10941    * another potential fix is to just remove this check here, and let
10942    * code doing stacking order changes inside the destruction sequence
10943    * of an actor continue doing the work.
10944    *
10945    * the third fix is to silently bail out early from every
10946    * set_child_*_sibling() and set_child_at_index() method, and avoid
10947    * doing work.
10948    *
10949    * I have a preference for the second solution, since it involves the
10950    * least amount of work, and the least amount of code duplication.
10951    *
10952    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10953    */
10954   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10955     {
10956       g_warning ("The actor '%s' is currently being destroyed, and "
10957                  "cannot be added as a child of another actor.",
10958                  _clutter_actor_get_debug_name (child));
10959       return;
10960     }
10961 #endif
10962
10963   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10964   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10965   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10966   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10967   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10968
10969   old_first_child = self->priv->first_child;
10970   old_last_child = self->priv->last_child;
10971
10972   g_object_freeze_notify (G_OBJECT (self));
10973
10974   if (create_meta)
10975     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10976
10977   g_object_ref_sink (child);
10978   child->priv->parent = NULL;
10979   child->priv->next_sibling = NULL;
10980   child->priv->prev_sibling = NULL;
10981
10982   /* delegate the actual insertion */
10983   add_func (self, child, data);
10984
10985   g_assert (child->priv->parent == self);
10986
10987   self->priv->n_children += 1;
10988
10989   self->priv->age += 1;
10990
10991   /* if push_internal() has been called then we automatically set
10992    * the flag on the actor
10993    */
10994   if (self->priv->internal_child)
10995     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10996
10997   /* clutter_actor_reparent() will emit ::parent-set for us */
10998   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10999     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11000
11001   if (check_state)
11002     {
11003       /* If parent is mapped or realized, we need to also be mapped or
11004        * realized once we're inside the parent.
11005        */
11006       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11007
11008       /* propagate the parent's text direction to the child */
11009       text_dir = clutter_actor_get_text_direction (self);
11010       clutter_actor_set_text_direction (child, text_dir);
11011     }
11012
11013   if (child->priv->show_on_set_parent)
11014     clutter_actor_show (child);
11015
11016   if (CLUTTER_ACTOR_IS_MAPPED (child))
11017     clutter_actor_queue_redraw (child);
11018
11019   /* maintain the invariant that if an actor needs layout,
11020    * its parents do as well
11021    */
11022   if (child->priv->needs_width_request ||
11023       child->priv->needs_height_request ||
11024       child->priv->needs_allocation)
11025     {
11026       /* we work around the short-circuiting we do
11027        * in clutter_actor_queue_relayout() since we
11028        * want to force a relayout
11029        */
11030       child->priv->needs_width_request = TRUE;
11031       child->priv->needs_height_request = TRUE;
11032       child->priv->needs_allocation = TRUE;
11033
11034       clutter_actor_queue_relayout (child->priv->parent);
11035     }
11036
11037   if (emit_actor_added)
11038     g_signal_emit_by_name (self, "actor-added", child);
11039
11040   if (notify_first_last)
11041     {
11042       if (old_first_child != self->priv->first_child)
11043         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11044
11045       if (old_last_child != self->priv->last_child)
11046         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11047     }
11048
11049   g_object_thaw_notify (G_OBJECT (self));
11050 }
11051
11052 /**
11053  * clutter_actor_add_child:
11054  * @self: a #ClutterActor
11055  * @child: a #ClutterActor
11056  *
11057  * Adds @child to the children of @self.
11058  *
11059  * This function will acquire a reference on @child that will only
11060  * be released when calling clutter_actor_remove_child().
11061  *
11062  * This function will take into consideration the #ClutterActor:depth
11063  * of @child, and will keep the list of children sorted.
11064  *
11065  * This function will emit the #ClutterContainer::actor-added signal
11066  * on @self.
11067  *
11068  * Since: 1.10
11069  */
11070 void
11071 clutter_actor_add_child (ClutterActor *self,
11072                          ClutterActor *child)
11073 {
11074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11075   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11076   g_return_if_fail (self != child);
11077   g_return_if_fail (child->priv->parent == NULL);
11078
11079   clutter_actor_add_child_internal (self, child,
11080                                     ADD_CHILD_DEFAULT_FLAGS,
11081                                     insert_child_at_depth,
11082                                     NULL);
11083 }
11084
11085 /**
11086  * clutter_actor_insert_child_at_index:
11087  * @self: a #ClutterActor
11088  * @child: a #ClutterActor
11089  * @index_: the index
11090  *
11091  * Inserts @child into the list of children of @self, using the
11092  * given @index_. If @index_ is greater than the number of children
11093  * in @self, or is less than 0, then the new child is added at the end.
11094  *
11095  * This function will acquire a reference on @child that will only
11096  * be released when calling clutter_actor_remove_child().
11097  *
11098  * This function will not take into consideration the #ClutterActor:depth
11099  * of @child.
11100  *
11101  * This function will emit the #ClutterContainer::actor-added signal
11102  * on @self.
11103  *
11104  * Since: 1.10
11105  */
11106 void
11107 clutter_actor_insert_child_at_index (ClutterActor *self,
11108                                      ClutterActor *child,
11109                                      gint          index_)
11110 {
11111   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11112   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11113   g_return_if_fail (self != child);
11114   g_return_if_fail (child->priv->parent == NULL);
11115
11116   clutter_actor_add_child_internal (self, child,
11117                                     ADD_CHILD_DEFAULT_FLAGS,
11118                                     insert_child_at_index,
11119                                     GINT_TO_POINTER (index_));
11120 }
11121
11122 /**
11123  * clutter_actor_insert_child_above:
11124  * @self: a #ClutterActor
11125  * @child: a #ClutterActor
11126  * @sibling: (allow-none): a child of @self, or %NULL
11127  *
11128  * Inserts @child into the list of children of @self, above another
11129  * child of @self or, if @sibling is %NULL, above all the children
11130  * of @self.
11131  *
11132  * This function will acquire a reference on @child that will only
11133  * be released when calling clutter_actor_remove_child().
11134  *
11135  * This function will not take into consideration the #ClutterActor:depth
11136  * of @child.
11137  *
11138  * This function will emit the #ClutterContainer::actor-added signal
11139  * on @self.
11140  *
11141  * Since: 1.10
11142  */
11143 void
11144 clutter_actor_insert_child_above (ClutterActor *self,
11145                                   ClutterActor *child,
11146                                   ClutterActor *sibling)
11147 {
11148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11149   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11150   g_return_if_fail (self != child);
11151   g_return_if_fail (child != sibling);
11152   g_return_if_fail (child->priv->parent == NULL);
11153   g_return_if_fail (sibling == NULL ||
11154                     (CLUTTER_IS_ACTOR (sibling) &&
11155                      sibling->priv->parent == self));
11156
11157   clutter_actor_add_child_internal (self, child,
11158                                     ADD_CHILD_DEFAULT_FLAGS,
11159                                     insert_child_above,
11160                                     sibling);
11161 }
11162
11163 /**
11164  * clutter_actor_insert_child_below:
11165  * @self: a #ClutterActor
11166  * @child: a #ClutterActor
11167  * @sibling: (allow-none): a child of @self, or %NULL
11168  *
11169  * Inserts @child into the list of children of @self, below another
11170  * child of @self or, if @sibling is %NULL, below all the children
11171  * of @self.
11172  *
11173  * This function will acquire a reference on @child that will only
11174  * be released when calling clutter_actor_remove_child().
11175  *
11176  * This function will not take into consideration the #ClutterActor:depth
11177  * of @child.
11178  *
11179  * This function will emit the #ClutterContainer::actor-added signal
11180  * on @self.
11181  *
11182  * Since: 1.10
11183  */
11184 void
11185 clutter_actor_insert_child_below (ClutterActor *self,
11186                                   ClutterActor *child,
11187                                   ClutterActor *sibling)
11188 {
11189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11190   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11191   g_return_if_fail (self != child);
11192   g_return_if_fail (child != sibling);
11193   g_return_if_fail (child->priv->parent == NULL);
11194   g_return_if_fail (sibling == NULL ||
11195                     (CLUTTER_IS_ACTOR (sibling) &&
11196                      sibling->priv->parent == self));
11197
11198   clutter_actor_add_child_internal (self, child,
11199                                     ADD_CHILD_DEFAULT_FLAGS,
11200                                     insert_child_below,
11201                                     sibling);
11202 }
11203
11204 /**
11205  * clutter_actor_set_parent:
11206  * @self: A #ClutterActor
11207  * @parent: A new #ClutterActor parent
11208  *
11209  * Sets the parent of @self to @parent.
11210  *
11211  * This function will result in @parent acquiring a reference on @self,
11212  * eventually by sinking its floating reference first. The reference
11213  * will be released by clutter_actor_unparent().
11214  *
11215  * This function should only be called by legacy #ClutterActor<!-- -->s
11216  * implementing the #ClutterContainer interface.
11217  *
11218  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11219  */
11220 void
11221 clutter_actor_set_parent (ClutterActor *self,
11222                           ClutterActor *parent)
11223 {
11224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11225   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11226   g_return_if_fail (self != parent);
11227   g_return_if_fail (self->priv->parent == NULL);
11228
11229   /* as this function will be called inside ClutterContainer::add
11230    * implementations or when building up a composite actor, we have
11231    * to preserve the old behaviour, and not create child meta or
11232    * emit the ::actor-added signal, to avoid recursion or double
11233    * emissions
11234    */
11235   clutter_actor_add_child_internal (parent, self,
11236                                     ADD_CHILD_LEGACY_FLAGS,
11237                                     insert_child_at_depth,
11238                                     NULL);
11239 }
11240
11241 /**
11242  * clutter_actor_get_parent:
11243  * @self: A #ClutterActor
11244  *
11245  * Retrieves the parent of @self.
11246  *
11247  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11248  *  if no parent is set
11249  */
11250 ClutterActor *
11251 clutter_actor_get_parent (ClutterActor *self)
11252 {
11253   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11254
11255   return self->priv->parent;
11256 }
11257
11258 /**
11259  * clutter_actor_get_paint_visibility:
11260  * @self: A #ClutterActor
11261  *
11262  * Retrieves the 'paint' visibility of an actor recursively checking for non
11263  * visible parents.
11264  *
11265  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11266  *
11267  * Return Value: %TRUE if the actor is visibile and will be painted.
11268  *
11269  * Since: 0.8.4
11270  */
11271 gboolean
11272 clutter_actor_get_paint_visibility (ClutterActor *actor)
11273 {
11274   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11275
11276   return CLUTTER_ACTOR_IS_MAPPED (actor);
11277 }
11278
11279 /**
11280  * clutter_actor_remove_child:
11281  * @self: a #ClutterActor
11282  * @child: a #ClutterActor
11283  *
11284  * Removes @child from the children of @self.
11285  *
11286  * This function will release the reference added by
11287  * clutter_actor_add_child(), so if you want to keep using @child
11288  * you will have to acquire a referenced on it before calling this
11289  * function.
11290  *
11291  * This function will emit the #ClutterContainer::actor-removed
11292  * signal on @self.
11293  *
11294  * Since: 1.10
11295  */
11296 void
11297 clutter_actor_remove_child (ClutterActor *self,
11298                             ClutterActor *child)
11299 {
11300   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11301   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11302   g_return_if_fail (self != child);
11303   g_return_if_fail (child->priv->parent != NULL);
11304   g_return_if_fail (child->priv->parent == self);
11305
11306   clutter_actor_remove_child_internal (self, child,
11307                                        REMOVE_CHILD_DEFAULT_FLAGS);
11308 }
11309
11310 /**
11311  * clutter_actor_remove_all_children:
11312  * @self: a #ClutterActor
11313  *
11314  * Removes all children of @self.
11315  *
11316  * This function releases the reference added by inserting a child actor
11317  * in the list of children of @self.
11318  *
11319  * If the reference count of a child drops to zero, the child will be
11320  * destroyed. If you want to ensure the destruction of all the children
11321  * of @self, use clutter_actor_destroy_all_children().
11322  *
11323  * Since: 1.10
11324  */
11325 void
11326 clutter_actor_remove_all_children (ClutterActor *self)
11327 {
11328   ClutterActorIter iter;
11329
11330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11331
11332   if (self->priv->n_children == 0)
11333     return;
11334
11335   g_object_freeze_notify (G_OBJECT (self));
11336
11337   clutter_actor_iter_init (&iter, self);
11338   while (clutter_actor_iter_next (&iter, NULL))
11339     clutter_actor_iter_remove (&iter);
11340
11341   g_object_thaw_notify (G_OBJECT (self));
11342
11343   /* sanity check */
11344   g_assert (self->priv->first_child == NULL);
11345   g_assert (self->priv->last_child == NULL);
11346   g_assert (self->priv->n_children == 0);
11347 }
11348
11349 /**
11350  * clutter_actor_destroy_all_children:
11351  * @self: a #ClutterActor
11352  *
11353  * Destroys all children of @self.
11354  *
11355  * This function releases the reference added by inserting a child
11356  * actor in the list of children of @self, and ensures that the
11357  * #ClutterActor::destroy signal is emitted on each child of the
11358  * actor.
11359  *
11360  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11361  * when its reference count drops to 0; the default handler of the
11362  * #ClutterActor::destroy signal will destroy all the children of an
11363  * actor. This function ensures that all children are destroyed, instead
11364  * of just removed from @self, unlike clutter_actor_remove_all_children()
11365  * which will merely release the reference and remove each child.
11366  *
11367  * Unless you acquired an additional reference on each child of @self
11368  * prior to calling clutter_actor_remove_all_children() and want to reuse
11369  * the actors, you should use clutter_actor_destroy_all_children() in
11370  * order to make sure that children are destroyed and signal handlers
11371  * are disconnected even in cases where circular references prevent this
11372  * from automatically happening through reference counting alone.
11373  *
11374  * Since: 1.10
11375  */
11376 void
11377 clutter_actor_destroy_all_children (ClutterActor *self)
11378 {
11379   ClutterActorIter iter;
11380
11381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11382
11383   if (self->priv->n_children == 0)
11384     return;
11385
11386   g_object_freeze_notify (G_OBJECT (self));
11387
11388   clutter_actor_iter_init (&iter, self);
11389   while (clutter_actor_iter_next (&iter, NULL))
11390     clutter_actor_iter_destroy (&iter);
11391
11392   g_object_thaw_notify (G_OBJECT (self));
11393
11394   /* sanity check */
11395   g_assert (self->priv->first_child == NULL);
11396   g_assert (self->priv->last_child == NULL);
11397   g_assert (self->priv->n_children == 0);
11398 }
11399
11400 typedef struct _InsertBetweenData {
11401   ClutterActor *prev_sibling;
11402   ClutterActor *next_sibling;
11403 } InsertBetweenData;
11404
11405 static void
11406 insert_child_between (ClutterActor *self,
11407                       ClutterActor *child,
11408                       gpointer      data_)
11409 {
11410   InsertBetweenData *data = data_;
11411   ClutterActor *prev_sibling = data->prev_sibling;
11412   ClutterActor *next_sibling = data->next_sibling;
11413
11414   child->priv->parent = self;
11415   child->priv->prev_sibling = prev_sibling;
11416   child->priv->next_sibling = next_sibling;
11417
11418   if (prev_sibling != NULL)
11419     prev_sibling->priv->next_sibling = child;
11420
11421   if (next_sibling != NULL)
11422     next_sibling->priv->prev_sibling = child;
11423
11424   if (child->priv->prev_sibling == NULL)
11425     self->priv->first_child = child;
11426
11427   if (child->priv->next_sibling == NULL)
11428     self->priv->last_child = child;
11429 }
11430
11431 /**
11432  * clutter_actor_replace_child:
11433  * @self: a #ClutterActor
11434  * @old_child: the child of @self to replace
11435  * @new_child: the #ClutterActor to replace @old_child
11436  *
11437  * Replaces @old_child with @new_child in the list of children of @self.
11438  *
11439  * Since: 1.10
11440  */
11441 void
11442 clutter_actor_replace_child (ClutterActor *self,
11443                              ClutterActor *old_child,
11444                              ClutterActor *new_child)
11445 {
11446   ClutterActor *prev_sibling, *next_sibling;
11447   InsertBetweenData clos;
11448
11449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11451   g_return_if_fail (old_child->priv->parent == self);
11452   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11453   g_return_if_fail (old_child != new_child);
11454   g_return_if_fail (new_child != self);
11455   g_return_if_fail (new_child->priv->parent == NULL);
11456
11457   prev_sibling = old_child->priv->prev_sibling;
11458   next_sibling = old_child->priv->next_sibling;
11459   clutter_actor_remove_child_internal (self, old_child,
11460                                        REMOVE_CHILD_DEFAULT_FLAGS);
11461
11462   clos.prev_sibling = prev_sibling;
11463   clos.next_sibling = next_sibling;
11464   clutter_actor_add_child_internal (self, new_child,
11465                                     ADD_CHILD_DEFAULT_FLAGS,
11466                                     insert_child_between,
11467                                     &clos);
11468 }
11469
11470 /**
11471  * clutter_actor_unparent:
11472  * @self: a #ClutterActor
11473  *
11474  * Removes the parent of @self.
11475  *
11476  * This will cause the parent of @self to release the reference
11477  * acquired when calling clutter_actor_set_parent(), so if you
11478  * want to keep @self you will have to acquire a reference of
11479  * your own, through g_object_ref().
11480  *
11481  * This function should only be called by legacy #ClutterActor<!-- -->s
11482  * implementing the #ClutterContainer interface.
11483  *
11484  * Since: 0.1.1
11485  *
11486  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11487  */
11488 void
11489 clutter_actor_unparent (ClutterActor *self)
11490 {
11491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11492
11493   if (self->priv->parent == NULL)
11494     return;
11495
11496   clutter_actor_remove_child_internal (self->priv->parent, self,
11497                                        REMOVE_CHILD_LEGACY_FLAGS);
11498 }
11499
11500 /**
11501  * clutter_actor_reparent:
11502  * @self: a #ClutterActor
11503  * @new_parent: the new #ClutterActor parent
11504  *
11505  * Resets the parent actor of @self.
11506  *
11507  * This function is logically equivalent to calling clutter_actor_unparent()
11508  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11509  * ensures the child is not finalized when unparented, and emits the
11510  * #ClutterActor::parent-set signal only once.
11511  *
11512  * In reality, calling this function is less useful than it sounds, as some
11513  * application code may rely on changes in the intermediate state between
11514  * removal and addition of the actor from its old parent to the @new_parent.
11515  * Thus, it is strongly encouraged to avoid using this function in application
11516  * code.
11517  *
11518  * Since: 0.2
11519  *
11520  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11521  *   clutter_actor_add_child() instead; remember to take a reference on
11522  *   the actor being removed before calling clutter_actor_remove_child()
11523  *   to avoid the reference count dropping to zero and the actor being
11524  *   destroyed.
11525  */
11526 void
11527 clutter_actor_reparent (ClutterActor *self,
11528                         ClutterActor *new_parent)
11529 {
11530   ClutterActorPrivate *priv;
11531
11532   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11533   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11534   g_return_if_fail (self != new_parent);
11535
11536   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11537     {
11538       g_warning ("Cannot set a parent on a toplevel actor");
11539       return;
11540     }
11541
11542   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11543     {
11544       g_warning ("Cannot set a parent currently being destroyed");
11545       return;
11546     }
11547
11548   priv = self->priv;
11549
11550   if (priv->parent != new_parent)
11551     {
11552       ClutterActor *old_parent;
11553
11554       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11555
11556       old_parent = priv->parent;
11557
11558       g_object_ref (self);
11559
11560       if (old_parent != NULL)
11561         {
11562          /* go through the Container implementation if this is a regular
11563           * child and not an internal one
11564           */
11565          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11566            {
11567              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11568
11569              /* this will have to call unparent() */
11570              clutter_container_remove_actor (parent, self);
11571            }
11572          else
11573            clutter_actor_remove_child_internal (old_parent, self,
11574                                                 REMOVE_CHILD_LEGACY_FLAGS);
11575         }
11576
11577       /* Note, will call set_parent() */
11578       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11579         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11580       else
11581         clutter_actor_add_child_internal (new_parent, self,
11582                                           ADD_CHILD_LEGACY_FLAGS,
11583                                           insert_child_at_depth,
11584                                           NULL);
11585
11586       /* we emit the ::parent-set signal once */
11587       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11588
11589       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11590
11591       /* the IN_REPARENT flag suspends state updates */
11592       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11593
11594       g_object_unref (self);
11595    }
11596 }
11597
11598 /**
11599  * clutter_actor_contains:
11600  * @self: A #ClutterActor
11601  * @descendant: A #ClutterActor, possibly contained in @self
11602  *
11603  * Determines if @descendant is contained inside @self (either as an
11604  * immediate child, or as a deeper descendant). If @self and
11605  * @descendant point to the same actor then it will also return %TRUE.
11606  *
11607  * Return value: whether @descendent is contained within @self
11608  *
11609  * Since: 1.4
11610  */
11611 gboolean
11612 clutter_actor_contains (ClutterActor *self,
11613                         ClutterActor *descendant)
11614 {
11615   ClutterActor *actor;
11616
11617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11618   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11619
11620   for (actor = descendant; actor; actor = actor->priv->parent)
11621     if (actor == self)
11622       return TRUE;
11623
11624   return FALSE;
11625 }
11626
11627 /**
11628  * clutter_actor_set_child_above_sibling:
11629  * @self: a #ClutterActor
11630  * @child: a #ClutterActor child of @self
11631  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11632  *
11633  * Sets @child to be above @sibling in the list of children of @self.
11634  *
11635  * If @sibling is %NULL, @child will be the new last child of @self.
11636  *
11637  * This function is logically equivalent to removing @child and using
11638  * clutter_actor_insert_child_above(), but it will not emit signals
11639  * or change state on @child.
11640  *
11641  * Since: 1.10
11642  */
11643 void
11644 clutter_actor_set_child_above_sibling (ClutterActor *self,
11645                                        ClutterActor *child,
11646                                        ClutterActor *sibling)
11647 {
11648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11649   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11650   g_return_if_fail (child->priv->parent == self);
11651   g_return_if_fail (child != sibling);
11652   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11653
11654   if (sibling != NULL)
11655     g_return_if_fail (sibling->priv->parent == self);
11656
11657   /* we don't want to change the state of child, or emit signals, or
11658    * regenerate ChildMeta instances here, but we still want to follow
11659    * the correct sequence of steps encoded in remove_child() and
11660    * add_child(), so that correctness is ensured, and we only go
11661    * through one known code path.
11662    */
11663   g_object_ref (child);
11664   clutter_actor_remove_child_internal (self, child, 0);
11665   clutter_actor_add_child_internal (self, child,
11666                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11667                                     insert_child_above,
11668                                     sibling);
11669
11670   clutter_actor_queue_relayout (self);
11671 }
11672
11673 /**
11674  * clutter_actor_set_child_below_sibling:
11675  * @self: a #ClutterActor
11676  * @child: a #ClutterActor child of @self
11677  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11678  *
11679  * Sets @child to be below @sibling in the list of children of @self.
11680  *
11681  * If @sibling is %NULL, @child will be the new first child of @self.
11682  *
11683  * This function is logically equivalent to removing @self and using
11684  * clutter_actor_insert_child_below(), but it will not emit signals
11685  * or change state on @child.
11686  *
11687  * Since: 1.10
11688  */
11689 void
11690 clutter_actor_set_child_below_sibling (ClutterActor *self,
11691                                        ClutterActor *child,
11692                                        ClutterActor *sibling)
11693 {
11694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11695   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11696   g_return_if_fail (child->priv->parent == self);
11697   g_return_if_fail (child != sibling);
11698   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11699
11700   if (sibling != NULL)
11701     g_return_if_fail (sibling->priv->parent == self);
11702
11703   /* see the comment in set_child_above_sibling() */
11704   g_object_ref (child);
11705   clutter_actor_remove_child_internal (self, child, 0);
11706   clutter_actor_add_child_internal (self, child,
11707                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11708                                     insert_child_below,
11709                                     sibling);
11710
11711   clutter_actor_queue_relayout (self);
11712 }
11713
11714 /**
11715  * clutter_actor_set_child_at_index:
11716  * @self: a #ClutterActor
11717  * @child: a #ClutterActor child of @self
11718  * @index_: the new index for @child
11719  *
11720  * Changes the index of @child in the list of children of @self.
11721  *
11722  * This function is logically equivalent to removing @child and
11723  * calling clutter_actor_insert_child_at_index(), but it will not
11724  * emit signals or change state on @child.
11725  *
11726  * Since: 1.10
11727  */
11728 void
11729 clutter_actor_set_child_at_index (ClutterActor *self,
11730                                   ClutterActor *child,
11731                                   gint          index_)
11732 {
11733   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11734   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11735   g_return_if_fail (child->priv->parent == self);
11736   g_return_if_fail (index_ <= self->priv->n_children);
11737
11738   g_object_ref (child);
11739   clutter_actor_remove_child_internal (self, child, 0);
11740   clutter_actor_add_child_internal (self, child,
11741                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11742                                     insert_child_at_index,
11743                                     GINT_TO_POINTER (index_));
11744
11745   clutter_actor_queue_relayout (self);
11746 }
11747
11748 /**
11749  * clutter_actor_raise:
11750  * @self: A #ClutterActor
11751  * @below: (allow-none): A #ClutterActor to raise above.
11752  *
11753  * Puts @self above @below.
11754  *
11755  * Both actors must have the same parent, and the parent must implement
11756  * the #ClutterContainer interface
11757  *
11758  * This function calls clutter_container_raise_child() internally.
11759  *
11760  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11761  */
11762 void
11763 clutter_actor_raise (ClutterActor *self,
11764                      ClutterActor *below)
11765 {
11766   ClutterActor *parent;
11767
11768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11769
11770   parent = clutter_actor_get_parent (self);
11771   if (parent == NULL)
11772     {
11773       g_warning ("%s: Actor '%s' is not inside a container",
11774                  G_STRFUNC,
11775                  _clutter_actor_get_debug_name (self));
11776       return;
11777     }
11778
11779   if (below != NULL)
11780     {
11781       if (parent != clutter_actor_get_parent (below))
11782         {
11783           g_warning ("%s Actor '%s' is not in the same container as "
11784                      "actor '%s'",
11785                      G_STRFUNC,
11786                      _clutter_actor_get_debug_name (self),
11787                      _clutter_actor_get_debug_name (below));
11788           return;
11789         }
11790     }
11791
11792   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11793 }
11794
11795 /**
11796  * clutter_actor_lower:
11797  * @self: A #ClutterActor
11798  * @above: (allow-none): A #ClutterActor to lower below
11799  *
11800  * Puts @self below @above.
11801  *
11802  * Both actors must have the same parent, and the parent must implement
11803  * the #ClutterContainer interface.
11804  *
11805  * This function calls clutter_container_lower_child() internally.
11806  *
11807  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11808  */
11809 void
11810 clutter_actor_lower (ClutterActor *self,
11811                      ClutterActor *above)
11812 {
11813   ClutterActor *parent;
11814
11815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11816
11817   parent = clutter_actor_get_parent (self);
11818   if (parent == NULL)
11819     {
11820       g_warning ("%s: Actor of type %s is not inside a container",
11821                  G_STRFUNC,
11822                  _clutter_actor_get_debug_name (self));
11823       return;
11824     }
11825
11826   if (above)
11827     {
11828       if (parent != clutter_actor_get_parent (above))
11829         {
11830           g_warning ("%s: Actor '%s' is not in the same container as "
11831                      "actor '%s'",
11832                      G_STRFUNC,
11833                      _clutter_actor_get_debug_name (self),
11834                      _clutter_actor_get_debug_name (above));
11835           return;
11836         }
11837     }
11838
11839   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11840 }
11841
11842 /**
11843  * clutter_actor_raise_top:
11844  * @self: A #ClutterActor
11845  *
11846  * Raises @self to the top.
11847  *
11848  * This function calls clutter_actor_raise() internally.
11849  *
11850  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11851  *   a %NULL sibling, instead.
11852  */
11853 void
11854 clutter_actor_raise_top (ClutterActor *self)
11855 {
11856   clutter_actor_raise (self, NULL);
11857 }
11858
11859 /**
11860  * clutter_actor_lower_bottom:
11861  * @self: A #ClutterActor
11862  *
11863  * Lowers @self to the bottom.
11864  *
11865  * This function calls clutter_actor_lower() internally.
11866  *
11867  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11868  *   a %NULL sibling, instead.
11869  */
11870 void
11871 clutter_actor_lower_bottom (ClutterActor *self)
11872 {
11873   clutter_actor_lower (self, NULL);
11874 }
11875
11876 /*
11877  * Event handling
11878  */
11879
11880 /**
11881  * clutter_actor_event:
11882  * @actor: a #ClutterActor
11883  * @event: a #ClutterEvent
11884  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11885  *
11886  * This function is used to emit an event on the main stage.
11887  * You should rarely need to use this function, except for
11888  * synthetising events.
11889  *
11890  * Return value: the return value from the signal emission: %TRUE
11891  *   if the actor handled the event, or %FALSE if the event was
11892  *   not handled
11893  *
11894  * Since: 0.6
11895  */
11896 gboolean
11897 clutter_actor_event (ClutterActor *actor,
11898                      ClutterEvent *event,
11899                      gboolean      capture)
11900 {
11901   gboolean retval = FALSE;
11902   gint signal_num = -1;
11903
11904   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11905   g_return_val_if_fail (event != NULL, FALSE);
11906
11907   g_object_ref (actor);
11908
11909   if (capture)
11910     {
11911       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11912                      event,
11913                      &retval);
11914       goto out;
11915     }
11916
11917   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11918
11919   if (!retval)
11920     {
11921       switch (event->type)
11922         {
11923         case CLUTTER_NOTHING:
11924           break;
11925         case CLUTTER_BUTTON_PRESS:
11926           signal_num = BUTTON_PRESS_EVENT;
11927           break;
11928         case CLUTTER_BUTTON_RELEASE:
11929           signal_num = BUTTON_RELEASE_EVENT;
11930           break;
11931         case CLUTTER_SCROLL:
11932           signal_num = SCROLL_EVENT;
11933           break;
11934         case CLUTTER_KEY_PRESS:
11935           signal_num = KEY_PRESS_EVENT;
11936           break;
11937         case CLUTTER_KEY_RELEASE:
11938           signal_num = KEY_RELEASE_EVENT;
11939           break;
11940         case CLUTTER_MOTION:
11941           signal_num = MOTION_EVENT;
11942           break;
11943         case CLUTTER_ENTER:
11944           signal_num = ENTER_EVENT;
11945           break;
11946         case CLUTTER_LEAVE:
11947           signal_num = LEAVE_EVENT;
11948           break;
11949         case CLUTTER_DELETE:
11950         case CLUTTER_DESTROY_NOTIFY:
11951         case CLUTTER_CLIENT_MESSAGE:
11952         default:
11953           signal_num = -1;
11954           break;
11955         }
11956
11957       if (signal_num != -1)
11958         g_signal_emit (actor, actor_signals[signal_num], 0,
11959                        event, &retval);
11960     }
11961
11962 out:
11963   g_object_unref (actor);
11964
11965   return retval;
11966 }
11967
11968 /**
11969  * clutter_actor_set_reactive:
11970  * @actor: a #ClutterActor
11971  * @reactive: whether the actor should be reactive to events
11972  *
11973  * Sets @actor as reactive. Reactive actors will receive events.
11974  *
11975  * Since: 0.6
11976  */
11977 void
11978 clutter_actor_set_reactive (ClutterActor *actor,
11979                             gboolean      reactive)
11980 {
11981   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11982
11983   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11984     return;
11985
11986   if (reactive)
11987     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11988   else
11989     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11990
11991   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11992 }
11993
11994 /**
11995  * clutter_actor_get_reactive:
11996  * @actor: a #ClutterActor
11997  *
11998  * Checks whether @actor is marked as reactive.
11999  *
12000  * Return value: %TRUE if the actor is reactive
12001  *
12002  * Since: 0.6
12003  */
12004 gboolean
12005 clutter_actor_get_reactive (ClutterActor *actor)
12006 {
12007   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12008
12009   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12010 }
12011
12012 /**
12013  * clutter_actor_get_anchor_point:
12014  * @self: a #ClutterActor
12015  * @anchor_x: (out): return location for the X coordinate of the anchor point
12016  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12017  *
12018  * Gets the current anchor point of the @actor in pixels.
12019  *
12020  * Since: 0.6
12021  */
12022 void
12023 clutter_actor_get_anchor_point (ClutterActor *self,
12024                                 gfloat       *anchor_x,
12025                                 gfloat       *anchor_y)
12026 {
12027   const ClutterTransformInfo *info;
12028
12029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12030
12031   info = _clutter_actor_get_transform_info_or_defaults (self);
12032   clutter_anchor_coord_get_units (self, &info->anchor,
12033                                   anchor_x,
12034                                   anchor_y,
12035                                   NULL);
12036 }
12037
12038 /**
12039  * clutter_actor_set_anchor_point:
12040  * @self: a #ClutterActor
12041  * @anchor_x: X coordinate of the anchor point
12042  * @anchor_y: Y coordinate of the anchor point
12043  *
12044  * Sets an anchor point for @self. The anchor point is a point in the
12045  * coordinate space of an actor to which the actor position within its
12046  * parent is relative; the default is (0, 0), i.e. the top-left corner
12047  * of the actor.
12048  *
12049  * Since: 0.6
12050  */
12051 void
12052 clutter_actor_set_anchor_point (ClutterActor *self,
12053                                 gfloat        anchor_x,
12054                                 gfloat        anchor_y)
12055 {
12056   ClutterTransformInfo *info;
12057   ClutterActorPrivate *priv;
12058   gboolean changed = FALSE;
12059   gfloat old_anchor_x, old_anchor_y;
12060   GObject *obj;
12061
12062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12063
12064   obj = G_OBJECT (self);
12065   priv = self->priv;
12066   info = _clutter_actor_get_transform_info (self);
12067
12068   g_object_freeze_notify (obj);
12069
12070   clutter_anchor_coord_get_units (self, &info->anchor,
12071                                   &old_anchor_x,
12072                                   &old_anchor_y,
12073                                   NULL);
12074
12075   if (info->anchor.is_fractional)
12076     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12077
12078   if (old_anchor_x != anchor_x)
12079     {
12080       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12081       changed = TRUE;
12082     }
12083
12084   if (old_anchor_y != anchor_y)
12085     {
12086       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12087       changed = TRUE;
12088     }
12089
12090   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12091
12092   if (changed)
12093     {
12094       priv->transform_valid = FALSE;
12095       clutter_actor_queue_redraw (self);
12096     }
12097
12098   g_object_thaw_notify (obj);
12099 }
12100
12101 /**
12102  * clutter_actor_get_anchor_point_gravity:
12103  * @self: a #ClutterActor
12104  *
12105  * Retrieves the anchor position expressed as a #ClutterGravity. If
12106  * the anchor point was specified using pixels or units this will
12107  * return %CLUTTER_GRAVITY_NONE.
12108  *
12109  * Return value: the #ClutterGravity used by the anchor point
12110  *
12111  * Since: 1.0
12112  */
12113 ClutterGravity
12114 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12115 {
12116   const ClutterTransformInfo *info;
12117
12118   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12119
12120   info = _clutter_actor_get_transform_info_or_defaults (self);
12121
12122   return clutter_anchor_coord_get_gravity (&info->anchor);
12123 }
12124
12125 /**
12126  * clutter_actor_move_anchor_point:
12127  * @self: a #ClutterActor
12128  * @anchor_x: X coordinate of the anchor point
12129  * @anchor_y: Y coordinate of the anchor point
12130  *
12131  * Sets an anchor point for the actor, and adjusts the actor postion so that
12132  * the relative position of the actor toward its parent remains the same.
12133  *
12134  * Since: 0.6
12135  */
12136 void
12137 clutter_actor_move_anchor_point (ClutterActor *self,
12138                                  gfloat        anchor_x,
12139                                  gfloat        anchor_y)
12140 {
12141   gfloat old_anchor_x, old_anchor_y;
12142   const ClutterTransformInfo *info;
12143
12144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12145
12146   info = _clutter_actor_get_transform_info (self);
12147   clutter_anchor_coord_get_units (self, &info->anchor,
12148                                   &old_anchor_x,
12149                                   &old_anchor_y,
12150                                   NULL);
12151
12152   g_object_freeze_notify (G_OBJECT (self));
12153
12154   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12155
12156   if (self->priv->position_set)
12157     clutter_actor_move_by (self,
12158                            anchor_x - old_anchor_x,
12159                            anchor_y - old_anchor_y);
12160
12161   g_object_thaw_notify (G_OBJECT (self));
12162 }
12163
12164 /**
12165  * clutter_actor_move_anchor_point_from_gravity:
12166  * @self: a #ClutterActor
12167  * @gravity: #ClutterGravity.
12168  *
12169  * Sets an anchor point on the actor based on the given gravity, adjusting the
12170  * actor postion so that its relative position within its parent remains
12171  * unchanged.
12172  *
12173  * Since version 1.0 the anchor point will be stored as a gravity so
12174  * that if the actor changes size then the anchor point will move. For
12175  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12176  * and later double the size of the actor, the anchor point will move
12177  * to the bottom right.
12178  *
12179  * Since: 0.6
12180  */
12181 void
12182 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12183                                               ClutterGravity  gravity)
12184 {
12185   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12186   const ClutterTransformInfo *info;
12187   ClutterActorPrivate *priv;
12188
12189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12190
12191   priv = self->priv;
12192   info = _clutter_actor_get_transform_info (self);
12193
12194   g_object_freeze_notify (G_OBJECT (self));
12195
12196   clutter_anchor_coord_get_units (self, &info->anchor,
12197                                   &old_anchor_x,
12198                                   &old_anchor_y,
12199                                   NULL);
12200   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12201   clutter_anchor_coord_get_units (self, &info->anchor,
12202                                   &new_anchor_x,
12203                                   &new_anchor_y,
12204                                   NULL);
12205
12206   if (priv->position_set)
12207     clutter_actor_move_by (self,
12208                            new_anchor_x - old_anchor_x,
12209                            new_anchor_y - old_anchor_y);
12210
12211   g_object_thaw_notify (G_OBJECT (self));
12212 }
12213
12214 /**
12215  * clutter_actor_set_anchor_point_from_gravity:
12216  * @self: a #ClutterActor
12217  * @gravity: #ClutterGravity.
12218  *
12219  * Sets an anchor point on the actor, based on the given gravity (this is a
12220  * convenience function wrapping clutter_actor_set_anchor_point()).
12221  *
12222  * Since version 1.0 the anchor point will be stored as a gravity so
12223  * that if the actor changes size then the anchor point will move. For
12224  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12225  * and later double the size of the actor, the anchor point will move
12226  * to the bottom right.
12227  *
12228  * Since: 0.6
12229  */
12230 void
12231 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12232                                              ClutterGravity  gravity)
12233 {
12234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12235
12236   if (gravity == CLUTTER_GRAVITY_NONE)
12237     clutter_actor_set_anchor_point (self, 0, 0);
12238   else
12239     {
12240       GObject *obj = G_OBJECT (self);
12241       ClutterTransformInfo *info;
12242
12243       g_object_freeze_notify (obj);
12244
12245       info = _clutter_actor_get_transform_info (self);
12246       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12247
12248       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12249       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12250       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12251
12252       self->priv->transform_valid = FALSE;
12253
12254       clutter_actor_queue_redraw (self);
12255
12256       g_object_thaw_notify (obj);
12257     }
12258 }
12259
12260 static void
12261 clutter_container_iface_init (ClutterContainerIface *iface)
12262 {
12263   /* we don't override anything, as ClutterContainer already has a default
12264    * implementation that we can use, and which calls into our own API.
12265    */
12266 }
12267
12268 typedef enum
12269 {
12270   PARSE_X,
12271   PARSE_Y,
12272   PARSE_WIDTH,
12273   PARSE_HEIGHT,
12274   PARSE_ANCHOR_X,
12275   PARSE_ANCHOR_Y
12276 } ParseDimension;
12277
12278 static gfloat
12279 parse_units (ClutterActor   *self,
12280              ParseDimension  dimension,
12281              JsonNode       *node)
12282 {
12283   GValue value = G_VALUE_INIT;
12284   gfloat retval = 0;
12285
12286   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12287     return 0;
12288
12289   json_node_get_value (node, &value);
12290
12291   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12292     {
12293       retval = (gfloat) g_value_get_int64 (&value);
12294     }
12295   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12296     {
12297       retval = g_value_get_double (&value);
12298     }
12299   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12300     {
12301       ClutterUnits units;
12302       gboolean res;
12303
12304       res = clutter_units_from_string (&units, g_value_get_string (&value));
12305       if (res)
12306         retval = clutter_units_to_pixels (&units);
12307       else
12308         {
12309           g_warning ("Invalid value '%s': integers, strings or floating point "
12310                      "values can be used for the x, y, width and height "
12311                      "properties. Valid modifiers for strings are 'px', 'mm', "
12312                      "'pt' and 'em'.",
12313                      g_value_get_string (&value));
12314           retval = 0;
12315         }
12316     }
12317   else
12318     {
12319       g_warning ("Invalid value of type '%s': integers, strings of floating "
12320                  "point values can be used for the x, y, width, height "
12321                  "anchor-x and anchor-y properties.",
12322                  g_type_name (G_VALUE_TYPE (&value)));
12323     }
12324
12325   g_value_unset (&value);
12326
12327   return retval;
12328 }
12329
12330 typedef struct {
12331   ClutterRotateAxis axis;
12332
12333   gdouble angle;
12334
12335   gfloat center_x;
12336   gfloat center_y;
12337   gfloat center_z;
12338 } RotationInfo;
12339
12340 static inline gboolean
12341 parse_rotation_array (ClutterActor *actor,
12342                       JsonArray    *array,
12343                       RotationInfo *info)
12344 {
12345   JsonNode *element;
12346
12347   if (json_array_get_length (array) != 2)
12348     return FALSE;
12349
12350   /* angle */
12351   element = json_array_get_element (array, 0);
12352   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12353     info->angle = json_node_get_double (element);
12354   else
12355     return FALSE;
12356
12357   /* center */
12358   element = json_array_get_element (array, 1);
12359   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12360     {
12361       JsonArray *center = json_node_get_array (element);
12362
12363       if (json_array_get_length (center) != 2)
12364         return FALSE;
12365
12366       switch (info->axis)
12367         {
12368         case CLUTTER_X_AXIS:
12369           info->center_y = parse_units (actor, PARSE_Y,
12370                                         json_array_get_element (center, 0));
12371           info->center_z = parse_units (actor, PARSE_Y,
12372                                         json_array_get_element (center, 1));
12373           return TRUE;
12374
12375         case CLUTTER_Y_AXIS:
12376           info->center_x = parse_units (actor, PARSE_X,
12377                                         json_array_get_element (center, 0));
12378           info->center_z = parse_units (actor, PARSE_X,
12379                                         json_array_get_element (center, 1));
12380           return TRUE;
12381
12382         case CLUTTER_Z_AXIS:
12383           info->center_x = parse_units (actor, PARSE_X,
12384                                         json_array_get_element (center, 0));
12385           info->center_y = parse_units (actor, PARSE_Y,
12386                                         json_array_get_element (center, 1));
12387           return TRUE;
12388         }
12389     }
12390
12391   return FALSE;
12392 }
12393
12394 static gboolean
12395 parse_rotation (ClutterActor *actor,
12396                 JsonNode     *node,
12397                 RotationInfo *info)
12398 {
12399   JsonArray *array;
12400   guint len, i;
12401   gboolean retval = FALSE;
12402
12403   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12404     {
12405       g_warning ("Invalid node of type '%s' found, expecting an array",
12406                  json_node_type_name (node));
12407       return FALSE;
12408     }
12409
12410   array = json_node_get_array (node);
12411   len = json_array_get_length (array);
12412
12413   for (i = 0; i < len; i++)
12414     {
12415       JsonNode *element = json_array_get_element (array, i);
12416       JsonObject *object;
12417       JsonNode *member;
12418
12419       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12420         {
12421           g_warning ("Invalid node of type '%s' found, expecting an object",
12422                      json_node_type_name (element));
12423           return FALSE;
12424         }
12425
12426       object = json_node_get_object (element);
12427
12428       if (json_object_has_member (object, "x-axis"))
12429         {
12430           member = json_object_get_member (object, "x-axis");
12431
12432           info->axis = CLUTTER_X_AXIS;
12433
12434           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12435             {
12436               info->angle = json_node_get_double (member);
12437               retval = TRUE;
12438             }
12439           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12440             retval = parse_rotation_array (actor,
12441                                            json_node_get_array (member),
12442                                            info);
12443           else
12444             retval = FALSE;
12445         }
12446       else if (json_object_has_member (object, "y-axis"))
12447         {
12448           member = json_object_get_member (object, "y-axis");
12449
12450           info->axis = CLUTTER_Y_AXIS;
12451
12452           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12453             {
12454               info->angle = json_node_get_double (member);
12455               retval = TRUE;
12456             }
12457           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12458             retval = parse_rotation_array (actor,
12459                                            json_node_get_array (member),
12460                                            info);
12461           else
12462             retval = FALSE;
12463         }
12464       else if (json_object_has_member (object, "z-axis"))
12465         {
12466           member = json_object_get_member (object, "z-axis");
12467
12468           info->axis = CLUTTER_Z_AXIS;
12469
12470           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12471             {
12472               info->angle = json_node_get_double (member);
12473               retval = TRUE;
12474             }
12475           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12476             retval = parse_rotation_array (actor,
12477                                            json_node_get_array (member),
12478                                            info);
12479           else
12480             retval = FALSE;
12481         }
12482     }
12483
12484   return retval;
12485 }
12486
12487 static GSList *
12488 parse_actor_metas (ClutterScript *script,
12489                    ClutterActor  *actor,
12490                    JsonNode      *node)
12491 {
12492   GList *elements, *l;
12493   GSList *retval = NULL;
12494
12495   if (!JSON_NODE_HOLDS_ARRAY (node))
12496     return NULL;
12497
12498   elements = json_array_get_elements (json_node_get_array (node));
12499
12500   for (l = elements; l != NULL; l = l->next)
12501     {
12502       JsonNode *element = l->data;
12503       const gchar *id_ = _clutter_script_get_id_from_node (element);
12504       GObject *meta;
12505
12506       if (id_ == NULL || *id_ == '\0')
12507         continue;
12508
12509       meta = clutter_script_get_object (script, id_);
12510       if (meta == NULL)
12511         continue;
12512
12513       retval = g_slist_prepend (retval, meta);
12514     }
12515
12516   g_list_free (elements);
12517
12518   return g_slist_reverse (retval);
12519 }
12520
12521 static GSList *
12522 parse_behaviours (ClutterScript *script,
12523                   ClutterActor  *actor,
12524                   JsonNode      *node)
12525 {
12526   GList *elements, *l;
12527   GSList *retval = NULL;
12528
12529   if (!JSON_NODE_HOLDS_ARRAY (node))
12530     return NULL;
12531
12532   elements = json_array_get_elements (json_node_get_array (node));
12533
12534   for (l = elements; l != NULL; l = l->next)
12535     {
12536       JsonNode *element = l->data;
12537       const gchar *id_ = _clutter_script_get_id_from_node (element);
12538       GObject *behaviour;
12539
12540       if (id_ == NULL || *id_ == '\0')
12541         continue;
12542
12543       behaviour = clutter_script_get_object (script, id_);
12544       if (behaviour == NULL)
12545         continue;
12546
12547       retval = g_slist_prepend (retval, behaviour);
12548     }
12549
12550   g_list_free (elements);
12551
12552   return g_slist_reverse (retval);
12553 }
12554
12555 static gboolean
12556 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12557                                  ClutterScript     *script,
12558                                  GValue            *value,
12559                                  const gchar       *name,
12560                                  JsonNode          *node)
12561 {
12562   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12563   gboolean retval = FALSE;
12564
12565   if ((name[0] == 'x' && name[1] == '\0') ||
12566       (name[0] == 'y' && name[1] == '\0') ||
12567       (strcmp (name, "width") == 0) ||
12568       (strcmp (name, "height") == 0) ||
12569       (strcmp (name, "anchor_x") == 0) ||
12570       (strcmp (name, "anchor_y") == 0))
12571     {
12572       ParseDimension dimension;
12573       gfloat units;
12574
12575       if (name[0] == 'x')
12576         dimension = PARSE_X;
12577       else if (name[0] == 'y')
12578         dimension = PARSE_Y;
12579       else if (name[0] == 'w')
12580         dimension = PARSE_WIDTH;
12581       else if (name[0] == 'h')
12582         dimension = PARSE_HEIGHT;
12583       else if (name[0] == 'a' && name[7] == 'x')
12584         dimension = PARSE_ANCHOR_X;
12585       else if (name[0] == 'a' && name[7] == 'y')
12586         dimension = PARSE_ANCHOR_Y;
12587       else
12588         return FALSE;
12589
12590       units = parse_units (actor, dimension, node);
12591
12592       /* convert back to pixels: all properties are pixel-based */
12593       g_value_init (value, G_TYPE_FLOAT);
12594       g_value_set_float (value, units);
12595
12596       retval = TRUE;
12597     }
12598   else if (strcmp (name, "rotation") == 0)
12599     {
12600       RotationInfo *info;
12601
12602       info = g_slice_new0 (RotationInfo);
12603       retval = parse_rotation (actor, node, info);
12604
12605       if (retval)
12606         {
12607           g_value_init (value, G_TYPE_POINTER);
12608           g_value_set_pointer (value, info);
12609         }
12610       else
12611         g_slice_free (RotationInfo, info);
12612     }
12613   else if (strcmp (name, "behaviours") == 0)
12614     {
12615       GSList *l;
12616
12617 #ifdef CLUTTER_ENABLE_DEBUG
12618       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12619         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12620                                      "and it should not be used in newly "
12621                                      "written ClutterScript definitions.");
12622 #endif
12623
12624       l = parse_behaviours (script, actor, node);
12625
12626       g_value_init (value, G_TYPE_POINTER);
12627       g_value_set_pointer (value, l);
12628
12629       retval = TRUE;
12630     }
12631   else if (strcmp (name, "actions") == 0 ||
12632            strcmp (name, "constraints") == 0 ||
12633            strcmp (name, "effects") == 0)
12634     {
12635       GSList *l;
12636
12637       l = parse_actor_metas (script, actor, node);
12638
12639       g_value_init (value, G_TYPE_POINTER);
12640       g_value_set_pointer (value, l);
12641
12642       retval = TRUE;
12643     }
12644
12645   return retval;
12646 }
12647
12648 static void
12649 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12650                                    ClutterScript     *script,
12651                                    const gchar       *name,
12652                                    const GValue      *value)
12653 {
12654   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12655
12656 #ifdef CLUTTER_ENABLE_DEBUG
12657   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12658     {
12659       gchar *tmp = g_strdup_value_contents (value);
12660
12661       CLUTTER_NOTE (SCRIPT,
12662                     "in ClutterActor::set_custom_property('%s') = %s",
12663                     name,
12664                     tmp);
12665
12666       g_free (tmp);
12667     }
12668 #endif /* CLUTTER_ENABLE_DEBUG */
12669
12670   if (strcmp (name, "rotation") == 0)
12671     {
12672       RotationInfo *info;
12673
12674       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12675         return;
12676
12677       info = g_value_get_pointer (value);
12678
12679       clutter_actor_set_rotation (actor,
12680                                   info->axis, info->angle,
12681                                   info->center_x,
12682                                   info->center_y,
12683                                   info->center_z);
12684
12685       g_slice_free (RotationInfo, info);
12686
12687       return;
12688     }
12689
12690   if (strcmp (name, "behaviours") == 0)
12691     {
12692       GSList *behaviours, *l;
12693
12694       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12695         return;
12696
12697       behaviours = g_value_get_pointer (value);
12698       for (l = behaviours; l != NULL; l = l->next)
12699         {
12700           ClutterBehaviour *behaviour = l->data;
12701
12702           clutter_behaviour_apply (behaviour, actor);
12703         }
12704
12705       g_slist_free (behaviours);
12706
12707       return;
12708     }
12709
12710   if (strcmp (name, "actions") == 0 ||
12711       strcmp (name, "constraints") == 0 ||
12712       strcmp (name, "effects") == 0)
12713     {
12714       GSList *metas, *l;
12715
12716       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12717         return;
12718
12719       metas = g_value_get_pointer (value);
12720       for (l = metas; l != NULL; l = l->next)
12721         {
12722           if (name[0] == 'a')
12723             clutter_actor_add_action (actor, l->data);
12724
12725           if (name[0] == 'c')
12726             clutter_actor_add_constraint (actor, l->data);
12727
12728           if (name[0] == 'e')
12729             clutter_actor_add_effect (actor, l->data);
12730         }
12731
12732       g_slist_free (metas);
12733
12734       return;
12735     }
12736
12737   g_object_set_property (G_OBJECT (scriptable), name, value);
12738 }
12739
12740 static void
12741 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12742 {
12743   iface->parse_custom_node = clutter_actor_parse_custom_node;
12744   iface->set_custom_property = clutter_actor_set_custom_property;
12745 }
12746
12747 static ClutterActorMeta *
12748 get_meta_from_animation_property (ClutterActor  *actor,
12749                                   const gchar   *name,
12750                                   gchar        **name_p)
12751 {
12752   ClutterActorPrivate *priv = actor->priv;
12753   ClutterActorMeta *meta = NULL;
12754   gchar **tokens;
12755
12756   /* if this is not a special property, fall through */
12757   if (name[0] != '@')
12758     return NULL;
12759
12760   /* detect the properties named using the following spec:
12761    *
12762    *   @<section>.<meta-name>.<property-name>
12763    *
12764    * where <section> can be one of the following:
12765    *
12766    *   - actions
12767    *   - constraints
12768    *   - effects
12769    *
12770    * and <meta-name> is the name set on a specific ActorMeta
12771    */
12772
12773   tokens = g_strsplit (name + 1, ".", -1);
12774   if (tokens == NULL || g_strv_length (tokens) != 3)
12775     {
12776       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12777                     name + 1);
12778       g_strfreev (tokens);
12779       return NULL;
12780     }
12781
12782   if (strcmp (tokens[0], "actions") == 0)
12783     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12784
12785   if (strcmp (tokens[0], "constraints") == 0)
12786     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12787
12788   if (strcmp (tokens[0], "effects") == 0)
12789     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12790
12791   if (name_p != NULL)
12792     *name_p = g_strdup (tokens[2]);
12793
12794   CLUTTER_NOTE (ANIMATION,
12795                 "Looking for property '%s' of object '%s' in section '%s'",
12796                 tokens[2],
12797                 tokens[1],
12798                 tokens[0]);
12799
12800   g_strfreev (tokens);
12801
12802   return meta;
12803 }
12804
12805 static GParamSpec *
12806 clutter_actor_find_property (ClutterAnimatable *animatable,
12807                              const gchar       *property_name)
12808 {
12809   ClutterActorMeta *meta = NULL;
12810   GObjectClass *klass = NULL;
12811   GParamSpec *pspec = NULL;
12812   gchar *p_name = NULL;
12813
12814   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12815                                            property_name,
12816                                            &p_name);
12817
12818   if (meta != NULL)
12819     {
12820       klass = G_OBJECT_GET_CLASS (meta);
12821
12822       pspec = g_object_class_find_property (klass, p_name);
12823     }
12824   else
12825     {
12826       klass = G_OBJECT_GET_CLASS (animatable);
12827
12828       pspec = g_object_class_find_property (klass, property_name);
12829     }
12830
12831   g_free (p_name);
12832
12833   return pspec;
12834 }
12835
12836 static void
12837 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12838                                  const gchar       *property_name,
12839                                  GValue            *initial)
12840 {
12841   ClutterActorMeta *meta = NULL;
12842   gchar *p_name = NULL;
12843
12844   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12845                                            property_name,
12846                                            &p_name);
12847
12848   if (meta != NULL)
12849     g_object_get_property (G_OBJECT (meta), p_name, initial);
12850   else
12851     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12852
12853   g_free (p_name);
12854 }
12855
12856 /*
12857  * clutter_actor_set_animatable_property:
12858  * @actor: a #ClutterActor
12859  * @prop_id: the paramspec id
12860  * @value: the value to set
12861  * @pspec: the paramspec
12862  *
12863  * Sets values of animatable properties.
12864  *
12865  * This is a variant of clutter_actor_set_property() that gets called
12866  * by the #ClutterAnimatable implementation of #ClutterActor for the
12867  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12868  * #GParamSpec.
12869  *
12870  * Unlike the implementation of #GObjectClass.set_property(), this
12871  * function will not update the interval if a transition involving an
12872  * animatable property is in progress - this avoids cycles with the
12873  * transition API calling the public API.
12874  */
12875 static void
12876 clutter_actor_set_animatable_property (ClutterActor *actor,
12877                                        guint         prop_id,
12878                                        const GValue *value,
12879                                        GParamSpec   *pspec)
12880 {
12881   switch (prop_id)
12882     {
12883     case PROP_X:
12884       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12885       break;
12886
12887     case PROP_Y:
12888       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12889       break;
12890
12891     case PROP_WIDTH:
12892       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12893       break;
12894
12895     case PROP_HEIGHT:
12896       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12897       break;
12898
12899     case PROP_DEPTH:
12900       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12901       break;
12902
12903     case PROP_OPACITY:
12904       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12905       break;
12906
12907     case PROP_BACKGROUND_COLOR:
12908       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12909       break;
12910
12911     case PROP_SCALE_X:
12912       clutter_actor_set_scale_factor_internal (actor,
12913                                                g_value_get_double (value),
12914                                                pspec);
12915       break;
12916
12917     case PROP_SCALE_Y:
12918       clutter_actor_set_scale_factor_internal (actor,
12919                                                g_value_get_double (value),
12920                                                pspec);
12921       break;
12922
12923     case PROP_ROTATION_ANGLE_X:
12924       clutter_actor_set_rotation_angle_internal (actor,
12925                                                  CLUTTER_X_AXIS,
12926                                                  g_value_get_double (value));
12927       break;
12928
12929     case PROP_ROTATION_ANGLE_Y:
12930       clutter_actor_set_rotation_angle_internal (actor,
12931                                                  CLUTTER_Y_AXIS,
12932                                                  g_value_get_double (value));
12933       break;
12934
12935     case PROP_ROTATION_ANGLE_Z:
12936       clutter_actor_set_rotation_angle_internal (actor,
12937                                                  CLUTTER_Z_AXIS,
12938                                                  g_value_get_double (value));
12939       break;
12940
12941     default:
12942       g_object_set_property (G_OBJECT (actor), pspec->name, value);
12943       break;
12944     }
12945 }
12946
12947 static void
12948 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12949                                const gchar       *property_name,
12950                                const GValue      *final)
12951 {
12952   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12953   ClutterActorMeta *meta = NULL;
12954   gchar *p_name = NULL;
12955
12956   meta = get_meta_from_animation_property (actor,
12957                                            property_name,
12958                                            &p_name);
12959   if (meta != NULL)
12960     g_object_set_property (G_OBJECT (meta), p_name, final);
12961   else
12962     {
12963       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12964       GParamSpec *pspec;
12965
12966       pspec = g_object_class_find_property (obj_class, property_name);
12967
12968       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12969         {
12970           /* XXX - I'm going to the special hell for this */
12971           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12972         }
12973       else
12974         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12975     }
12976
12977   g_free (p_name);
12978 }
12979
12980 static void
12981 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12982 {
12983   iface->find_property = clutter_actor_find_property;
12984   iface->get_initial_state = clutter_actor_get_initial_state;
12985   iface->set_final_state = clutter_actor_set_final_state;
12986 }
12987
12988 /**
12989  * clutter_actor_transform_stage_point:
12990  * @self: A #ClutterActor
12991  * @x: (in): x screen coordinate of the point to unproject
12992  * @y: (in): y screen coordinate of the point to unproject
12993  * @x_out: (out): return location for the unprojected x coordinance
12994  * @y_out: (out): return location for the unprojected y coordinance
12995  *
12996  * This function translates screen coordinates (@x, @y) to
12997  * coordinates relative to the actor. For example, it can be used to translate
12998  * screen events from global screen coordinates into actor-local coordinates.
12999  *
13000  * The conversion can fail, notably if the transform stack results in the
13001  * actor being projected on the screen as a mere line.
13002  *
13003  * The conversion should not be expected to be pixel-perfect due to the
13004  * nature of the operation. In general the error grows when the skewing
13005  * of the actor rectangle on screen increases.
13006  *
13007  * <note><para>This function can be computationally intensive.</para></note>
13008  *
13009  * <note><para>This function only works when the allocation is up-to-date,
13010  * i.e. inside of paint().</para></note>
13011  *
13012  * Return value: %TRUE if conversion was successful.
13013  *
13014  * Since: 0.6
13015  */
13016 gboolean
13017 clutter_actor_transform_stage_point (ClutterActor *self,
13018                                      gfloat        x,
13019                                      gfloat        y,
13020                                      gfloat       *x_out,
13021                                      gfloat       *y_out)
13022 {
13023   ClutterVertex v[4];
13024   float ST[3][3];
13025   float RQ[3][3];
13026   int du, dv, xi, yi;
13027   float px, py;
13028   float xf, yf, wf, det;
13029   ClutterActorPrivate *priv;
13030
13031   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13032
13033   priv = self->priv;
13034
13035   /* This implementation is based on the quad -> quad projection algorithm
13036    * described by Paul Heckbert in:
13037    *
13038    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13039    *
13040    * and the sample implementation at:
13041    *
13042    *   http://www.cs.cmu.edu/~ph/src/texfund/
13043    *
13044    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13045    * quad to rectangle only, which significantly simplifies things; the
13046    * function calls have been unrolled, and most of the math is done in fixed
13047    * point.
13048    */
13049
13050   clutter_actor_get_abs_allocation_vertices (self, v);
13051
13052   /* Keeping these as ints simplifies the multiplication (no significant
13053    * loss of precision here).
13054    */
13055   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13056   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13057
13058   if (!du || !dv)
13059     return FALSE;
13060
13061 #define UX2FP(x)        (x)
13062 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13063
13064   /* First, find mapping from unit uv square to xy quadrilateral; this
13065    * equivalent to the pmap_square_quad() functions in the sample
13066    * implementation, which we can simplify, since our target is always
13067    * a rectangle.
13068    */
13069   px = v[0].x - v[1].x + v[3].x - v[2].x;
13070   py = v[0].y - v[1].y + v[3].y - v[2].y;
13071
13072   if (!px && !py)
13073     {
13074       /* affine transform */
13075       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13076       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13077       RQ[2][0] = UX2FP (v[0].x);
13078       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13079       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13080       RQ[2][1] = UX2FP (v[0].y);
13081       RQ[0][2] = 0;
13082       RQ[1][2] = 0;
13083       RQ[2][2] = 1.0;
13084     }
13085   else
13086     {
13087       /* projective transform */
13088       double dx1, dx2, dy1, dy2, del;
13089
13090       dx1 = UX2FP (v[1].x - v[3].x);
13091       dx2 = UX2FP (v[2].x - v[3].x);
13092       dy1 = UX2FP (v[1].y - v[3].y);
13093       dy2 = UX2FP (v[2].y - v[3].y);
13094
13095       del = DET2FP (dx1, dx2, dy1, dy2);
13096       if (!del)
13097         return FALSE;
13098
13099       /*
13100        * The division here needs to be done in floating point for
13101        * precisions reasons.
13102        */
13103       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13104       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13105       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13106       RQ[2][2] = 1.0;
13107       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13108       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13109       RQ[2][0] = UX2FP (v[0].x);
13110       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13111       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13112       RQ[2][1] = UX2FP (v[0].y);
13113     }
13114
13115   /*
13116    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13117    * square. Since our rectangle is based at 0,0 we only need to scale.
13118    */
13119   RQ[0][0] /= du;
13120   RQ[1][0] /= dv;
13121   RQ[0][1] /= du;
13122   RQ[1][1] /= dv;
13123   RQ[0][2] /= du;
13124   RQ[1][2] /= dv;
13125
13126   /*
13127    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13128    * inverse of that.
13129    */
13130   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13131   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13132   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13133   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13134   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13135   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13136   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13137   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13138   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13139
13140   /*
13141    * Check the resulting matrix is OK.
13142    */
13143   det = (RQ[0][0] * ST[0][0])
13144       + (RQ[0][1] * ST[0][1])
13145       + (RQ[0][2] * ST[0][2]);
13146   if (!det)
13147     return FALSE;
13148
13149   /*
13150    * Now transform our point with the ST matrix; the notional w
13151    * coordinate is 1, hence the last part is simply added.
13152    */
13153   xi = (int) x;
13154   yi = (int) y;
13155
13156   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13157   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13158   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13159
13160   if (x_out)
13161     *x_out = xf / wf;
13162
13163   if (y_out)
13164     *y_out = yf / wf;
13165
13166 #undef UX2FP
13167 #undef DET2FP
13168
13169   return TRUE;
13170 }
13171
13172 /*
13173  * ClutterGeometry
13174  */
13175
13176 static ClutterGeometry*
13177 clutter_geometry_copy (const ClutterGeometry *geometry)
13178 {
13179   return g_slice_dup (ClutterGeometry, geometry);
13180 }
13181
13182 static void
13183 clutter_geometry_free (ClutterGeometry *geometry)
13184 {
13185   if (G_LIKELY (geometry != NULL))
13186     g_slice_free (ClutterGeometry, geometry);
13187 }
13188
13189 /**
13190  * clutter_geometry_union:
13191  * @geometry_a: a #ClutterGeometry
13192  * @geometry_b: another #ClutterGeometry
13193  * @result: (out): location to store the result
13194  *
13195  * Find the union of two rectangles represented as #ClutterGeometry.
13196  *
13197  * Since: 1.4
13198  */
13199 void
13200 clutter_geometry_union (const ClutterGeometry *geometry_a,
13201                         const ClutterGeometry *geometry_b,
13202                         ClutterGeometry       *result)
13203 {
13204   /* We don't try to handle rectangles that can't be represented
13205    * as a signed integer box */
13206   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13207   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13208   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13209                   geometry_b->x + (gint)geometry_b->width);
13210   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13211                   geometry_b->y + (gint)geometry_b->height);
13212   result->x = x_1;
13213   result->y = y_1;
13214   result->width = x_2 - x_1;
13215   result->height = y_2 - y_1;
13216 }
13217
13218 /**
13219  * clutter_geometry_intersects:
13220  * @geometry0: The first geometry to test
13221  * @geometry1: The second geometry to test
13222  *
13223  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13224  * they do else %FALSE.
13225  *
13226  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13227  * %FALSE.
13228  *
13229  * Since: 1.4
13230  */
13231 gboolean
13232 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13233                              const ClutterGeometry *geometry1)
13234 {
13235   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13236       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13237       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13238       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13239     return FALSE;
13240   else
13241     return TRUE;
13242 }
13243
13244 static gboolean
13245 clutter_geometry_progress (const GValue *a,
13246                            const GValue *b,
13247                            gdouble       progress,
13248                            GValue       *retval)
13249 {
13250   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13251   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13252   ClutterGeometry res = { 0, };
13253   gint a_width = a_geom->width;
13254   gint b_width = b_geom->width;
13255   gint a_height = a_geom->height;
13256   gint b_height = b_geom->height;
13257
13258   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13259   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13260
13261   res.width = a_width + (b_width - a_width) * progress;
13262   res.height = a_height + (b_height - a_height) * progress;
13263
13264   g_value_set_boxed (retval, &res);
13265
13266   return TRUE;
13267 }
13268
13269 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13270                                clutter_geometry_copy,
13271                                clutter_geometry_free,
13272                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13273
13274 /*
13275  * ClutterVertices
13276  */
13277
13278 /**
13279  * clutter_vertex_new:
13280  * @x: X coordinate
13281  * @y: Y coordinate
13282  * @z: Z coordinate
13283  *
13284  * Creates a new #ClutterVertex for the point in 3D space
13285  * identified by the 3 coordinates @x, @y, @z
13286  *
13287  * Return value: the newly allocate #ClutterVertex. Use
13288  *   clutter_vertex_free() to free the resources
13289  *
13290  * Since: 1.0
13291  */
13292 ClutterVertex *
13293 clutter_vertex_new (gfloat x,
13294                     gfloat y,
13295                     gfloat z)
13296 {
13297   ClutterVertex *vertex;
13298
13299   vertex = g_slice_new (ClutterVertex);
13300   clutter_vertex_init (vertex, x, y, z);
13301
13302   return vertex;
13303 }
13304
13305 /**
13306  * clutter_vertex_init:
13307  * @vertex: a #ClutterVertex
13308  * @x: X coordinate
13309  * @y: Y coordinate
13310  * @z: Z coordinate
13311  *
13312  * Initializes @vertex with the given coordinates.
13313  *
13314  * Since: 1.10
13315  */
13316 void
13317 clutter_vertex_init (ClutterVertex *vertex,
13318                      gfloat         x,
13319                      gfloat         y,
13320                      gfloat         z)
13321 {
13322   g_return_if_fail (vertex != NULL);
13323
13324   vertex->x = x;
13325   vertex->y = y;
13326   vertex->z = z;
13327 }
13328
13329 /**
13330  * clutter_vertex_copy:
13331  * @vertex: a #ClutterVertex
13332  *
13333  * Copies @vertex
13334  *
13335  * Return value: a newly allocated copy of #ClutterVertex. Use
13336  *   clutter_vertex_free() to free the allocated resources
13337  *
13338  * Since: 1.0
13339  */
13340 ClutterVertex *
13341 clutter_vertex_copy (const ClutterVertex *vertex)
13342 {
13343   if (G_LIKELY (vertex != NULL))
13344     return g_slice_dup (ClutterVertex, vertex);
13345
13346   return NULL;
13347 }
13348
13349 /**
13350  * clutter_vertex_free:
13351  * @vertex: a #ClutterVertex
13352  *
13353  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13354  *
13355  * Since: 1.0
13356  */
13357 void
13358 clutter_vertex_free (ClutterVertex *vertex)
13359 {
13360   if (G_UNLIKELY (vertex != NULL))
13361     g_slice_free (ClutterVertex, vertex);
13362 }
13363
13364 /**
13365  * clutter_vertex_equal:
13366  * @vertex_a: a #ClutterVertex
13367  * @vertex_b: a #ClutterVertex
13368  *
13369  * Compares @vertex_a and @vertex_b for equality
13370  *
13371  * Return value: %TRUE if the passed #ClutterVertex are equal
13372  *
13373  * Since: 1.0
13374  */
13375 gboolean
13376 clutter_vertex_equal (const ClutterVertex *vertex_a,
13377                       const ClutterVertex *vertex_b)
13378 {
13379   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13380
13381   if (vertex_a == vertex_b)
13382     return TRUE;
13383
13384   return vertex_a->x == vertex_b->x &&
13385          vertex_a->y == vertex_b->y &&
13386          vertex_a->z == vertex_b->z;
13387 }
13388
13389 static gboolean
13390 clutter_vertex_progress (const GValue *a,
13391                          const GValue *b,
13392                          gdouble       progress,
13393                          GValue       *retval)
13394 {
13395   const ClutterVertex *av = g_value_get_boxed (a);
13396   const ClutterVertex *bv = g_value_get_boxed (b);
13397   ClutterVertex res = { 0, };
13398
13399   res.x = av->x + (bv->x - av->x) * progress;
13400   res.y = av->y + (bv->y - av->y) * progress;
13401   res.z = av->z + (bv->z - av->z) * progress;
13402
13403   g_value_set_boxed (retval, &res);
13404
13405   return TRUE;
13406 }
13407
13408 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13409                                clutter_vertex_copy,
13410                                clutter_vertex_free,
13411                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13412
13413 /**
13414  * clutter_actor_is_rotated:
13415  * @self: a #ClutterActor
13416  *
13417  * Checks whether any rotation is applied to the actor.
13418  *
13419  * Return value: %TRUE if the actor is rotated.
13420  *
13421  * Since: 0.6
13422  */
13423 gboolean
13424 clutter_actor_is_rotated (ClutterActor *self)
13425 {
13426   const ClutterTransformInfo *info;
13427
13428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13429
13430   info = _clutter_actor_get_transform_info_or_defaults (self);
13431
13432   if (info->rx_angle || info->ry_angle || info->rz_angle)
13433     return TRUE;
13434
13435   return FALSE;
13436 }
13437
13438 /**
13439  * clutter_actor_is_scaled:
13440  * @self: a #ClutterActor
13441  *
13442  * Checks whether the actor is scaled in either dimension.
13443  *
13444  * Return value: %TRUE if the actor is scaled.
13445  *
13446  * Since: 0.6
13447  */
13448 gboolean
13449 clutter_actor_is_scaled (ClutterActor *self)
13450 {
13451   const ClutterTransformInfo *info;
13452
13453   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13454
13455   info = _clutter_actor_get_transform_info_or_defaults (self);
13456
13457   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13458     return TRUE;
13459
13460   return FALSE;
13461 }
13462
13463 ClutterActor *
13464 _clutter_actor_get_stage_internal (ClutterActor *actor)
13465 {
13466   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13467     actor = actor->priv->parent;
13468
13469   return actor;
13470 }
13471
13472 /**
13473  * clutter_actor_get_stage:
13474  * @actor: a #ClutterActor
13475  *
13476  * Retrieves the #ClutterStage where @actor is contained.
13477  *
13478  * Return value: (transfer none) (type Clutter.Stage): the stage
13479  *   containing the actor, or %NULL
13480  *
13481  * Since: 0.8
13482  */
13483 ClutterActor *
13484 clutter_actor_get_stage (ClutterActor *actor)
13485 {
13486   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13487
13488   return _clutter_actor_get_stage_internal (actor);
13489 }
13490
13491 /**
13492  * clutter_actor_allocate_available_size:
13493  * @self: a #ClutterActor
13494  * @x: the actor's X coordinate
13495  * @y: the actor's Y coordinate
13496  * @available_width: the maximum available width, or -1 to use the
13497  *   actor's natural width
13498  * @available_height: the maximum available height, or -1 to use the
13499  *   actor's natural height
13500  * @flags: flags controlling the allocation
13501  *
13502  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13503  * preferred size, but limiting it to the maximum available width
13504  * and height provided.
13505  *
13506  * This function will do the right thing when dealing with the
13507  * actor's request mode.
13508  *
13509  * The implementation of this function is equivalent to:
13510  *
13511  * |[
13512  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13513  *     {
13514  *       clutter_actor_get_preferred_width (self, available_height,
13515  *                                          &amp;min_width,
13516  *                                          &amp;natural_width);
13517  *       width = CLAMP (natural_width, min_width, available_width);
13518  *
13519  *       clutter_actor_get_preferred_height (self, width,
13520  *                                           &amp;min_height,
13521  *                                           &amp;natural_height);
13522  *       height = CLAMP (natural_height, min_height, available_height);
13523  *     }
13524  *   else
13525  *     {
13526  *       clutter_actor_get_preferred_height (self, available_width,
13527  *                                           &amp;min_height,
13528  *                                           &amp;natural_height);
13529  *       height = CLAMP (natural_height, min_height, available_height);
13530  *
13531  *       clutter_actor_get_preferred_width (self, height,
13532  *                                          &amp;min_width,
13533  *                                          &amp;natural_width);
13534  *       width = CLAMP (natural_width, min_width, available_width);
13535  *     }
13536  *
13537  *   box.x1 = x; box.y1 = y;
13538  *   box.x2 = box.x1 + available_width;
13539  *   box.y2 = box.y1 + available_height;
13540  *   clutter_actor_allocate (self, &amp;box, flags);
13541  * ]|
13542  *
13543  * This function can be used by fluid layout managers to allocate
13544  * an actor's preferred size without making it bigger than the area
13545  * available for the container.
13546  *
13547  * Since: 1.0
13548  */
13549 void
13550 clutter_actor_allocate_available_size (ClutterActor           *self,
13551                                        gfloat                  x,
13552                                        gfloat                  y,
13553                                        gfloat                  available_width,
13554                                        gfloat                  available_height,
13555                                        ClutterAllocationFlags  flags)
13556 {
13557   ClutterActorPrivate *priv;
13558   gfloat width, height;
13559   gfloat min_width, min_height;
13560   gfloat natural_width, natural_height;
13561   ClutterActorBox box;
13562
13563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13564
13565   priv = self->priv;
13566
13567   width = height = 0.0;
13568
13569   switch (priv->request_mode)
13570     {
13571     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13572       clutter_actor_get_preferred_width (self, available_height,
13573                                          &min_width,
13574                                          &natural_width);
13575       width  = CLAMP (natural_width, min_width, available_width);
13576
13577       clutter_actor_get_preferred_height (self, width,
13578                                           &min_height,
13579                                           &natural_height);
13580       height = CLAMP (natural_height, min_height, available_height);
13581       break;
13582
13583     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13584       clutter_actor_get_preferred_height (self, available_width,
13585                                           &min_height,
13586                                           &natural_height);
13587       height = CLAMP (natural_height, min_height, available_height);
13588
13589       clutter_actor_get_preferred_width (self, height,
13590                                          &min_width,
13591                                          &natural_width);
13592       width  = CLAMP (natural_width, min_width, available_width);
13593       break;
13594     }
13595
13596
13597   box.x1 = x;
13598   box.y1 = y;
13599   box.x2 = box.x1 + width;
13600   box.y2 = box.y1 + height;
13601   clutter_actor_allocate (self, &box, flags);
13602 }
13603
13604 /**
13605  * clutter_actor_allocate_preferred_size:
13606  * @self: a #ClutterActor
13607  * @flags: flags controlling the allocation
13608  *
13609  * Allocates the natural size of @self.
13610  *
13611  * This function is a utility call for #ClutterActor implementations
13612  * that allocates the actor's preferred natural size. It can be used
13613  * by fixed layout managers (like #ClutterGroup or so called
13614  * 'composite actors') inside the ClutterActor::allocate
13615  * implementation to give each child exactly how much space it
13616  * requires.
13617  *
13618  * This function is not meant to be used by applications. It is also
13619  * not meant to be used outside the implementation of the
13620  * ClutterActor::allocate virtual function.
13621  *
13622  * Since: 0.8
13623  */
13624 void
13625 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13626                                        ClutterAllocationFlags  flags)
13627 {
13628   gfloat actor_x, actor_y;
13629   gfloat natural_width, natural_height;
13630   ClutterActorBox actor_box;
13631
13632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13633
13634   actor_x = clutter_actor_get_x (self);
13635   actor_y = clutter_actor_get_y (self);
13636
13637   clutter_actor_get_preferred_size (self,
13638                                     NULL, NULL,
13639                                     &natural_width,
13640                                     &natural_height);
13641
13642   actor_box.x1 = actor_x;
13643   actor_box.y1 = actor_y;
13644   actor_box.x2 = actor_box.x1 + natural_width;
13645   actor_box.y2 = actor_box.y1 + natural_height;
13646
13647   clutter_actor_allocate (self, &actor_box, flags);
13648 }
13649
13650 /**
13651  * clutter_actor_allocate_align_fill:
13652  * @self: a #ClutterActor
13653  * @box: a #ClutterActorBox, containing the available width and height
13654  * @x_align: the horizontal alignment, between 0 and 1
13655  * @y_align: the vertical alignment, between 0 and 1
13656  * @x_fill: whether the actor should fill horizontally
13657  * @y_fill: whether the actor should fill vertically
13658  * @flags: allocation flags to be passed to clutter_actor_allocate()
13659  *
13660  * Allocates @self by taking into consideration the available allocation
13661  * area; an alignment factor on either axis; and whether the actor should
13662  * fill the allocation on either axis.
13663  *
13664  * The @box should contain the available allocation width and height;
13665  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13666  * allocation will be offset by their value.
13667  *
13668  * This function takes into consideration the geometry request specified by
13669  * the #ClutterActor:request-mode property, and the text direction.
13670  *
13671  * This function is useful for fluid layout managers, like #ClutterBinLayout
13672  * or #ClutterTableLayout
13673  *
13674  * Since: 1.4
13675  */
13676 void
13677 clutter_actor_allocate_align_fill (ClutterActor           *self,
13678                                    const ClutterActorBox  *box,
13679                                    gdouble                 x_align,
13680                                    gdouble                 y_align,
13681                                    gboolean                x_fill,
13682                                    gboolean                y_fill,
13683                                    ClutterAllocationFlags  flags)
13684 {
13685   ClutterActorPrivate *priv;
13686   ClutterActorBox allocation = { 0, };
13687   gfloat x_offset, y_offset;
13688   gfloat available_width, available_height;
13689   gfloat child_width, child_height;
13690
13691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13692   g_return_if_fail (box != NULL);
13693   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13694   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13695
13696   priv = self->priv;
13697
13698   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13699   clutter_actor_box_get_size (box, &available_width, &available_height);
13700
13701   if (available_width < 0)
13702     available_width = 0;
13703
13704   if (available_height < 0)
13705     available_height = 0;
13706
13707   if (x_fill)
13708     {
13709       allocation.x1 = x_offset;
13710       allocation.x2 = allocation.x1 + available_width;
13711     }
13712
13713   if (y_fill)
13714     {
13715       allocation.y1 = y_offset;
13716       allocation.y2 = allocation.y1 + available_height;
13717     }
13718
13719   /* if we are filling horizontally and vertically then we're done */
13720   if (x_fill && y_fill)
13721     goto out;
13722
13723   child_width = child_height = 0.0f;
13724
13725   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13726     {
13727       gfloat min_width, natural_width;
13728       gfloat min_height, natural_height;
13729
13730       clutter_actor_get_preferred_width (self, available_height,
13731                                          &min_width,
13732                                          &natural_width);
13733
13734       child_width = CLAMP (natural_width, min_width, available_width);
13735
13736       if (!y_fill)
13737         {
13738           clutter_actor_get_preferred_height (self, child_width,
13739                                               &min_height,
13740                                               &natural_height);
13741
13742           child_height = CLAMP (natural_height, min_height, available_height);
13743         }
13744     }
13745   else
13746     {
13747       gfloat min_width, natural_width;
13748       gfloat min_height, natural_height;
13749
13750       clutter_actor_get_preferred_height (self, available_width,
13751                                           &min_height,
13752                                           &natural_height);
13753
13754       child_height = CLAMP (natural_height, min_height, available_height);
13755
13756       if (!x_fill)
13757         {
13758           clutter_actor_get_preferred_width (self, child_height,
13759                                              &min_width,
13760                                              &natural_width);
13761
13762           child_width = CLAMP (natural_width, min_width, available_width);
13763         }
13764     }
13765
13766   /* invert the horizontal alignment for RTL languages */
13767   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13768     x_align = 1.0 - x_align;
13769
13770   if (!x_fill)
13771     {
13772       allocation.x1 = x_offset
13773                     + ((available_width - child_width) * x_align);
13774       allocation.x2 = allocation.x1 + child_width;
13775     }
13776
13777   if (!y_fill)
13778     {
13779       allocation.y1 = y_offset
13780                     + ((available_height - child_height) * y_align);
13781       allocation.y2 = allocation.y1 + child_height;
13782     }
13783
13784 out:
13785   clutter_actor_box_clamp_to_pixel (&allocation);
13786   clutter_actor_allocate (self, &allocation, flags);
13787 }
13788
13789 /**
13790  * clutter_actor_grab_key_focus:
13791  * @self: a #ClutterActor
13792  *
13793  * Sets the key focus of the #ClutterStage including @self
13794  * to this #ClutterActor.
13795  *
13796  * Since: 1.0
13797  */
13798 void
13799 clutter_actor_grab_key_focus (ClutterActor *self)
13800 {
13801   ClutterActor *stage;
13802
13803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13804
13805   stage = _clutter_actor_get_stage_internal (self);
13806   if (stage != NULL)
13807     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13808 }
13809
13810 /**
13811  * clutter_actor_get_pango_context:
13812  * @self: a #ClutterActor
13813  *
13814  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13815  * is already configured using the appropriate font map, resolution
13816  * and font options.
13817  *
13818  * Unlike clutter_actor_create_pango_context(), this context is owend
13819  * by the #ClutterActor and it will be updated each time the options
13820  * stored by the #ClutterBackend change.
13821  *
13822  * You can use the returned #PangoContext to create a #PangoLayout
13823  * and render text using cogl_pango_render_layout() to reuse the
13824  * glyphs cache also used by Clutter.
13825  *
13826  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13827  *   The returned #PangoContext is owned by the actor and should not be
13828  *   unreferenced by the application code
13829  *
13830  * Since: 1.0
13831  */
13832 PangoContext *
13833 clutter_actor_get_pango_context (ClutterActor *self)
13834 {
13835   ClutterActorPrivate *priv;
13836
13837   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13838
13839   priv = self->priv;
13840
13841   if (priv->pango_context != NULL)
13842     return priv->pango_context;
13843
13844   priv->pango_context = _clutter_context_get_pango_context ();
13845   g_object_ref (priv->pango_context);
13846
13847   return priv->pango_context;
13848 }
13849
13850 /**
13851  * clutter_actor_create_pango_context:
13852  * @self: a #ClutterActor
13853  *
13854  * Creates a #PangoContext for the given actor. The #PangoContext
13855  * is already configured using the appropriate font map, resolution
13856  * and font options.
13857  *
13858  * See also clutter_actor_get_pango_context().
13859  *
13860  * Return value: (transfer full): the newly created #PangoContext.
13861  *   Use g_object_unref() on the returned value to deallocate its
13862  *   resources
13863  *
13864  * Since: 1.0
13865  */
13866 PangoContext *
13867 clutter_actor_create_pango_context (ClutterActor *self)
13868 {
13869   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13870
13871   return _clutter_context_create_pango_context ();
13872 }
13873
13874 /**
13875  * clutter_actor_create_pango_layout:
13876  * @self: a #ClutterActor
13877  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13878  *
13879  * Creates a new #PangoLayout from the same #PangoContext used
13880  * by the #ClutterActor. The #PangoLayout is already configured
13881  * with the font map, resolution and font options, and the
13882  * given @text.
13883  *
13884  * If you want to keep around a #PangoLayout created by this
13885  * function you will have to connect to the #ClutterBackend::font-changed
13886  * and #ClutterBackend::resolution-changed signals, and call
13887  * pango_layout_context_changed() in response to them.
13888  *
13889  * Return value: (transfer full): the newly created #PangoLayout.
13890  *   Use g_object_unref() when done
13891  *
13892  * Since: 1.0
13893  */
13894 PangoLayout *
13895 clutter_actor_create_pango_layout (ClutterActor *self,
13896                                    const gchar  *text)
13897 {
13898   PangoContext *context;
13899   PangoLayout *layout;
13900
13901   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13902
13903   context = clutter_actor_get_pango_context (self);
13904   layout = pango_layout_new (context);
13905
13906   if (text)
13907     pango_layout_set_text (layout, text, -1);
13908
13909   return layout;
13910 }
13911
13912 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13913  * ClutterOffscreenEffect.
13914  */
13915 void
13916 _clutter_actor_set_opacity_override (ClutterActor *self,
13917                                      gint          opacity)
13918 {
13919   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13920
13921   self->priv->opacity_override = opacity;
13922 }
13923
13924 gint
13925 _clutter_actor_get_opacity_override (ClutterActor *self)
13926 {
13927   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13928
13929   return self->priv->opacity_override;
13930 }
13931
13932 /* Allows you to disable applying the actors model view transform during
13933  * a paint. Used by ClutterClone. */
13934 void
13935 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13936                                                 gboolean      enable)
13937 {
13938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13939
13940   self->priv->enable_model_view_transform = enable;
13941 }
13942
13943 void
13944 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13945                                           gboolean      enable)
13946 {
13947   ClutterActorPrivate *priv;
13948
13949   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13950
13951   priv = self->priv;
13952
13953   priv->enable_paint_unmapped = enable;
13954
13955   if (priv->enable_paint_unmapped)
13956     {
13957       /* Make sure that the parents of the widget are realized first;
13958        * otherwise checks in clutter_actor_update_map_state() will
13959        * fail.
13960        */
13961       clutter_actor_realize (self);
13962
13963       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13964     }
13965   else
13966     {
13967       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13968     }
13969 }
13970
13971 static void
13972 clutter_anchor_coord_get_units (ClutterActor      *self,
13973                                 const AnchorCoord *coord,
13974                                 gfloat            *x,
13975                                 gfloat            *y,
13976                                 gfloat            *z)
13977 {
13978   if (coord->is_fractional)
13979     {
13980       gfloat actor_width, actor_height;
13981
13982       clutter_actor_get_size (self, &actor_width, &actor_height);
13983
13984       if (x)
13985         *x = actor_width * coord->v.fraction.x;
13986
13987       if (y)
13988         *y = actor_height * coord->v.fraction.y;
13989
13990       if (z)
13991         *z = 0;
13992     }
13993   else
13994     {
13995       if (x)
13996         *x = coord->v.units.x;
13997
13998       if (y)
13999         *y = coord->v.units.y;
14000
14001       if (z)
14002         *z = coord->v.units.z;
14003     }
14004 }
14005
14006 static void
14007 clutter_anchor_coord_set_units (AnchorCoord *coord,
14008                                 gfloat       x,
14009                                 gfloat       y,
14010                                 gfloat       z)
14011 {
14012   coord->is_fractional = FALSE;
14013   coord->v.units.x = x;
14014   coord->v.units.y = y;
14015   coord->v.units.z = z;
14016 }
14017
14018 static ClutterGravity
14019 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14020 {
14021   if (coord->is_fractional)
14022     {
14023       if (coord->v.fraction.x == 0.0)
14024         {
14025           if (coord->v.fraction.y == 0.0)
14026             return CLUTTER_GRAVITY_NORTH_WEST;
14027           else if (coord->v.fraction.y == 0.5)
14028             return CLUTTER_GRAVITY_WEST;
14029           else if (coord->v.fraction.y == 1.0)
14030             return CLUTTER_GRAVITY_SOUTH_WEST;
14031           else
14032             return CLUTTER_GRAVITY_NONE;
14033         }
14034       else if (coord->v.fraction.x == 0.5)
14035         {
14036           if (coord->v.fraction.y == 0.0)
14037             return CLUTTER_GRAVITY_NORTH;
14038           else if (coord->v.fraction.y == 0.5)
14039             return CLUTTER_GRAVITY_CENTER;
14040           else if (coord->v.fraction.y == 1.0)
14041             return CLUTTER_GRAVITY_SOUTH;
14042           else
14043             return CLUTTER_GRAVITY_NONE;
14044         }
14045       else if (coord->v.fraction.x == 1.0)
14046         {
14047           if (coord->v.fraction.y == 0.0)
14048             return CLUTTER_GRAVITY_NORTH_EAST;
14049           else if (coord->v.fraction.y == 0.5)
14050             return CLUTTER_GRAVITY_EAST;
14051           else if (coord->v.fraction.y == 1.0)
14052             return CLUTTER_GRAVITY_SOUTH_EAST;
14053           else
14054             return CLUTTER_GRAVITY_NONE;
14055         }
14056       else
14057         return CLUTTER_GRAVITY_NONE;
14058     }
14059   else
14060     return CLUTTER_GRAVITY_NONE;
14061 }
14062
14063 static void
14064 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14065                                   ClutterGravity  gravity)
14066 {
14067   switch (gravity)
14068     {
14069     case CLUTTER_GRAVITY_NORTH:
14070       coord->v.fraction.x = 0.5;
14071       coord->v.fraction.y = 0.0;
14072       break;
14073
14074     case CLUTTER_GRAVITY_NORTH_EAST:
14075       coord->v.fraction.x = 1.0;
14076       coord->v.fraction.y = 0.0;
14077       break;
14078
14079     case CLUTTER_GRAVITY_EAST:
14080       coord->v.fraction.x = 1.0;
14081       coord->v.fraction.y = 0.5;
14082       break;
14083
14084     case CLUTTER_GRAVITY_SOUTH_EAST:
14085       coord->v.fraction.x = 1.0;
14086       coord->v.fraction.y = 1.0;
14087       break;
14088
14089     case CLUTTER_GRAVITY_SOUTH:
14090       coord->v.fraction.x = 0.5;
14091       coord->v.fraction.y = 1.0;
14092       break;
14093
14094     case CLUTTER_GRAVITY_SOUTH_WEST:
14095       coord->v.fraction.x = 0.0;
14096       coord->v.fraction.y = 1.0;
14097       break;
14098
14099     case CLUTTER_GRAVITY_WEST:
14100       coord->v.fraction.x = 0.0;
14101       coord->v.fraction.y = 0.5;
14102       break;
14103
14104     case CLUTTER_GRAVITY_NORTH_WEST:
14105       coord->v.fraction.x = 0.0;
14106       coord->v.fraction.y = 0.0;
14107       break;
14108
14109     case CLUTTER_GRAVITY_CENTER:
14110       coord->v.fraction.x = 0.5;
14111       coord->v.fraction.y = 0.5;
14112       break;
14113
14114     default:
14115       coord->v.fraction.x = 0.0;
14116       coord->v.fraction.y = 0.0;
14117       break;
14118     }
14119
14120   coord->is_fractional = TRUE;
14121 }
14122
14123 static gboolean
14124 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14125 {
14126   if (coord->is_fractional)
14127     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14128   else
14129     return (coord->v.units.x == 0.0
14130             && coord->v.units.y == 0.0
14131             && coord->v.units.z == 0.0);
14132 }
14133
14134 /**
14135  * clutter_actor_get_flags:
14136  * @self: a #ClutterActor
14137  *
14138  * Retrieves the flags set on @self
14139  *
14140  * Return value: a bitwise or of #ClutterActorFlags or 0
14141  *
14142  * Since: 1.0
14143  */
14144 ClutterActorFlags
14145 clutter_actor_get_flags (ClutterActor *self)
14146 {
14147   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14148
14149   return self->flags;
14150 }
14151
14152 /**
14153  * clutter_actor_set_flags:
14154  * @self: a #ClutterActor
14155  * @flags: the flags to set
14156  *
14157  * Sets @flags on @self
14158  *
14159  * This function will emit notifications for the changed properties
14160  *
14161  * Since: 1.0
14162  */
14163 void
14164 clutter_actor_set_flags (ClutterActor      *self,
14165                          ClutterActorFlags  flags)
14166 {
14167   ClutterActorFlags old_flags;
14168   GObject *obj;
14169   gboolean was_reactive_set, reactive_set;
14170   gboolean was_realized_set, realized_set;
14171   gboolean was_mapped_set, mapped_set;
14172   gboolean was_visible_set, visible_set;
14173
14174   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14175
14176   if (self->flags == flags)
14177     return;
14178
14179   obj = G_OBJECT (self);
14180   g_object_ref (obj);
14181   g_object_freeze_notify (obj);
14182
14183   old_flags = self->flags;
14184
14185   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14186   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14187   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14188   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14189
14190   self->flags |= flags;
14191
14192   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14193   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14194   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14195   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14196
14197   if (reactive_set != was_reactive_set)
14198     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14199
14200   if (realized_set != was_realized_set)
14201     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14202
14203   if (mapped_set != was_mapped_set)
14204     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14205
14206   if (visible_set != was_visible_set)
14207     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14208
14209   g_object_thaw_notify (obj);
14210   g_object_unref (obj);
14211 }
14212
14213 /**
14214  * clutter_actor_unset_flags:
14215  * @self: a #ClutterActor
14216  * @flags: the flags to unset
14217  *
14218  * Unsets @flags on @self
14219  *
14220  * This function will emit notifications for the changed properties
14221  *
14222  * Since: 1.0
14223  */
14224 void
14225 clutter_actor_unset_flags (ClutterActor      *self,
14226                            ClutterActorFlags  flags)
14227 {
14228   ClutterActorFlags old_flags;
14229   GObject *obj;
14230   gboolean was_reactive_set, reactive_set;
14231   gboolean was_realized_set, realized_set;
14232   gboolean was_mapped_set, mapped_set;
14233   gboolean was_visible_set, visible_set;
14234
14235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14236
14237   obj = G_OBJECT (self);
14238   g_object_freeze_notify (obj);
14239
14240   old_flags = self->flags;
14241
14242   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14243   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14244   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14245   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14246
14247   self->flags &= ~flags;
14248
14249   if (self->flags == old_flags)
14250     return;
14251
14252   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14253   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14254   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14255   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14256
14257   if (reactive_set != was_reactive_set)
14258     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14259
14260   if (realized_set != was_realized_set)
14261     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14262
14263   if (mapped_set != was_mapped_set)
14264     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14265
14266   if (visible_set != was_visible_set)
14267     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14268
14269   g_object_thaw_notify (obj);
14270 }
14271
14272 /**
14273  * clutter_actor_get_transformation_matrix:
14274  * @self: a #ClutterActor
14275  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14276  *
14277  * Retrieves the transformations applied to @self relative to its
14278  * parent.
14279  *
14280  * Since: 1.0
14281  */
14282 void
14283 clutter_actor_get_transformation_matrix (ClutterActor *self,
14284                                          CoglMatrix   *matrix)
14285 {
14286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14287
14288   cogl_matrix_init_identity (matrix);
14289
14290   _clutter_actor_apply_modelview_transform (self, matrix);
14291 }
14292
14293 void
14294 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14295                                    gboolean      is_in_clone_paint)
14296 {
14297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14298   self->priv->in_clone_paint = is_in_clone_paint;
14299 }
14300
14301 /**
14302  * clutter_actor_is_in_clone_paint:
14303  * @self: a #ClutterActor
14304  *
14305  * Checks whether @self is being currently painted by a #ClutterClone
14306  *
14307  * This function is useful only inside the ::paint virtual function
14308  * implementations or within handlers for the #ClutterActor::paint
14309  * signal
14310  *
14311  * This function should not be used by applications
14312  *
14313  * Return value: %TRUE if the #ClutterActor is currently being painted
14314  *   by a #ClutterClone, and %FALSE otherwise
14315  *
14316  * Since: 1.0
14317  */
14318 gboolean
14319 clutter_actor_is_in_clone_paint (ClutterActor *self)
14320 {
14321   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14322
14323   return self->priv->in_clone_paint;
14324 }
14325
14326 static gboolean
14327 set_direction_recursive (ClutterActor *actor,
14328                          gpointer      user_data)
14329 {
14330   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14331
14332   clutter_actor_set_text_direction (actor, text_dir);
14333
14334   return TRUE;
14335 }
14336
14337 /**
14338  * clutter_actor_set_text_direction:
14339  * @self: a #ClutterActor
14340  * @text_dir: the text direction for @self
14341  *
14342  * Sets the #ClutterTextDirection for an actor
14343  *
14344  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14345  *
14346  * If @self implements #ClutterContainer then this function will recurse
14347  * inside all the children of @self (including the internal ones).
14348  *
14349  * Composite actors not implementing #ClutterContainer, or actors requiring
14350  * special handling when the text direction changes, should connect to
14351  * the #GObject::notify signal for the #ClutterActor:text-direction property
14352  *
14353  * Since: 1.2
14354  */
14355 void
14356 clutter_actor_set_text_direction (ClutterActor         *self,
14357                                   ClutterTextDirection  text_dir)
14358 {
14359   ClutterActorPrivate *priv;
14360
14361   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14362   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14363
14364   priv = self->priv;
14365
14366   if (priv->text_direction != text_dir)
14367     {
14368       priv->text_direction = text_dir;
14369
14370       /* we need to emit the notify::text-direction first, so that
14371        * the sub-classes can catch that and do specific handling of
14372        * the text direction; see clutter_text_direction_changed_cb()
14373        * inside clutter-text.c
14374        */
14375       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14376
14377       _clutter_actor_foreach_child (self, set_direction_recursive,
14378                                     GINT_TO_POINTER (text_dir));
14379
14380       clutter_actor_queue_relayout (self);
14381     }
14382 }
14383
14384 void
14385 _clutter_actor_set_has_pointer (ClutterActor *self,
14386                                 gboolean      has_pointer)
14387 {
14388   ClutterActorPrivate *priv = self->priv;
14389
14390   if (priv->has_pointer != has_pointer)
14391     {
14392       priv->has_pointer = has_pointer;
14393
14394       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14395     }
14396 }
14397
14398 /**
14399  * clutter_actor_get_text_direction:
14400  * @self: a #ClutterActor
14401  *
14402  * Retrieves the value set using clutter_actor_set_text_direction()
14403  *
14404  * If no text direction has been previously set, the default text
14405  * direction, as returned by clutter_get_default_text_direction(), will
14406  * be returned instead
14407  *
14408  * Return value: the #ClutterTextDirection for the actor
14409  *
14410  * Since: 1.2
14411  */
14412 ClutterTextDirection
14413 clutter_actor_get_text_direction (ClutterActor *self)
14414 {
14415   ClutterActorPrivate *priv;
14416
14417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14418                         CLUTTER_TEXT_DIRECTION_LTR);
14419
14420   priv = self->priv;
14421
14422   /* if no direction has been set yet use the default */
14423   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14424     priv->text_direction = clutter_get_default_text_direction ();
14425
14426   return priv->text_direction;
14427 }
14428
14429 /**
14430  * clutter_actor_push_internal:
14431  * @self: a #ClutterActor
14432  *
14433  * Should be used by actors implementing the #ClutterContainer and with
14434  * internal children added through clutter_actor_set_parent(), for instance:
14435  *
14436  * |[
14437  *   static void
14438  *   my_actor_init (MyActor *self)
14439  *   {
14440  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14441  *
14442  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14443  *
14444  *     /&ast; calling clutter_actor_set_parent() now will result in
14445  *      &ast; the internal flag being set on a child of MyActor
14446  *      &ast;/
14447  *
14448  *     /&ast; internal child - a background texture &ast;/
14449  *     self->priv->background_tex = clutter_texture_new ();
14450  *     clutter_actor_set_parent (self->priv->background_tex,
14451  *                               CLUTTER_ACTOR (self));
14452  *
14453  *     /&ast; internal child - a label &ast;/
14454  *     self->priv->label = clutter_text_new ();
14455  *     clutter_actor_set_parent (self->priv->label,
14456  *                               CLUTTER_ACTOR (self));
14457  *
14458  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14459  *
14460  *     /&ast; calling clutter_actor_set_parent() now will not result in
14461  *      &ast; the internal flag being set on a child of MyActor
14462  *      &ast;/
14463  *   }
14464  * ]|
14465  *
14466  * This function will be used by Clutter to toggle an "internal child"
14467  * flag whenever clutter_actor_set_parent() is called; internal children
14468  * are handled differently by Clutter, specifically when destroying their
14469  * parent.
14470  *
14471  * Call clutter_actor_pop_internal() when you finished adding internal
14472  * children.
14473  *
14474  * Nested calls to clutter_actor_push_internal() are allowed, but each
14475  * one must by followed by a clutter_actor_pop_internal() call.
14476  *
14477  * Since: 1.2
14478  *
14479  * Deprecated: 1.10: All children of an actor are accessible through
14480  *   the #ClutterActor API, and #ClutterActor implements the
14481  *   #ClutterContainer interface, so this function is only useful
14482  *   for legacy containers overriding the default implementation.
14483  */
14484 void
14485 clutter_actor_push_internal (ClutterActor *self)
14486 {
14487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14488
14489   self->priv->internal_child += 1;
14490 }
14491
14492 /**
14493  * clutter_actor_pop_internal:
14494  * @self: a #ClutterActor
14495  *
14496  * Disables the effects of clutter_actor_push_internal().
14497  *
14498  * Since: 1.2
14499  *
14500  * Deprecated: 1.10: All children of an actor are accessible through
14501  *   the #ClutterActor API. This function is only useful for legacy
14502  *   containers overriding the default implementation of the
14503  *   #ClutterContainer interface.
14504  */
14505 void
14506 clutter_actor_pop_internal (ClutterActor *self)
14507 {
14508   ClutterActorPrivate *priv;
14509
14510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14511
14512   priv = self->priv;
14513
14514   if (priv->internal_child == 0)
14515     {
14516       g_warning ("Mismatched %s: you need to call "
14517                  "clutter_actor_push_composite() at least once before "
14518                  "calling this function", G_STRFUNC);
14519       return;
14520     }
14521
14522   priv->internal_child -= 1;
14523 }
14524
14525 /**
14526  * clutter_actor_has_pointer:
14527  * @self: a #ClutterActor
14528  *
14529  * Checks whether an actor contains the pointer of a
14530  * #ClutterInputDevice
14531  *
14532  * Return value: %TRUE if the actor contains the pointer, and
14533  *   %FALSE otherwise
14534  *
14535  * Since: 1.2
14536  */
14537 gboolean
14538 clutter_actor_has_pointer (ClutterActor *self)
14539 {
14540   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14541
14542   return self->priv->has_pointer;
14543 }
14544
14545 /* XXX: This is a workaround for not being able to break the ABI of
14546  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14547  * clutter_actor_queue_clipped_redraw() for details.
14548  */
14549 ClutterPaintVolume *
14550 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14551 {
14552   return g_object_get_data (G_OBJECT (self),
14553                             "-clutter-actor-queue-redraw-clip");
14554 }
14555
14556 void
14557 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14558                                       ClutterPaintVolume *clip)
14559 {
14560   g_object_set_data (G_OBJECT (self),
14561                      "-clutter-actor-queue-redraw-clip",
14562                      clip);
14563 }
14564
14565 /**
14566  * clutter_actor_has_allocation:
14567  * @self: a #ClutterActor
14568  *
14569  * Checks if the actor has an up-to-date allocation assigned to
14570  * it. This means that the actor should have an allocation: it's
14571  * visible and has a parent. It also means that there is no
14572  * outstanding relayout request in progress for the actor or its
14573  * children (There might be other outstanding layout requests in
14574  * progress that will cause the actor to get a new allocation
14575  * when the stage is laid out, however).
14576  *
14577  * If this function returns %FALSE, then the actor will normally
14578  * be allocated before it is next drawn on the screen.
14579  *
14580  * Return value: %TRUE if the actor has an up-to-date allocation
14581  *
14582  * Since: 1.4
14583  */
14584 gboolean
14585 clutter_actor_has_allocation (ClutterActor *self)
14586 {
14587   ClutterActorPrivate *priv;
14588
14589   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14590
14591   priv = self->priv;
14592
14593   return priv->parent != NULL &&
14594          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14595          !priv->needs_allocation;
14596 }
14597
14598 /**
14599  * clutter_actor_add_action:
14600  * @self: a #ClutterActor
14601  * @action: a #ClutterAction
14602  *
14603  * Adds @action to the list of actions applied to @self
14604  *
14605  * A #ClutterAction can only belong to one actor at a time
14606  *
14607  * The #ClutterActor will hold a reference on @action until either
14608  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14609  * is called
14610  *
14611  * Since: 1.4
14612  */
14613 void
14614 clutter_actor_add_action (ClutterActor  *self,
14615                           ClutterAction *action)
14616 {
14617   ClutterActorPrivate *priv;
14618
14619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14620   g_return_if_fail (CLUTTER_IS_ACTION (action));
14621
14622   priv = self->priv;
14623
14624   if (priv->actions == NULL)
14625     {
14626       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14627       priv->actions->actor = self;
14628     }
14629
14630   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14631
14632   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14633 }
14634
14635 /**
14636  * clutter_actor_add_action_with_name:
14637  * @self: a #ClutterActor
14638  * @name: the name to set on the action
14639  * @action: a #ClutterAction
14640  *
14641  * A convenience function for setting the name of a #ClutterAction
14642  * while adding it to the list of actions applied to @self
14643  *
14644  * This function is the logical equivalent of:
14645  *
14646  * |[
14647  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14648  *   clutter_actor_add_action (self, action);
14649  * ]|
14650  *
14651  * Since: 1.4
14652  */
14653 void
14654 clutter_actor_add_action_with_name (ClutterActor  *self,
14655                                     const gchar   *name,
14656                                     ClutterAction *action)
14657 {
14658   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14659   g_return_if_fail (name != NULL);
14660   g_return_if_fail (CLUTTER_IS_ACTION (action));
14661
14662   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14663   clutter_actor_add_action (self, action);
14664 }
14665
14666 /**
14667  * clutter_actor_remove_action:
14668  * @self: a #ClutterActor
14669  * @action: a #ClutterAction
14670  *
14671  * Removes @action from the list of actions applied to @self
14672  *
14673  * The reference held by @self on the #ClutterAction will be released
14674  *
14675  * Since: 1.4
14676  */
14677 void
14678 clutter_actor_remove_action (ClutterActor  *self,
14679                              ClutterAction *action)
14680 {
14681   ClutterActorPrivate *priv;
14682
14683   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14684   g_return_if_fail (CLUTTER_IS_ACTION (action));
14685
14686   priv = self->priv;
14687
14688   if (priv->actions == NULL)
14689     return;
14690
14691   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14692
14693   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14694 }
14695
14696 /**
14697  * clutter_actor_remove_action_by_name:
14698  * @self: a #ClutterActor
14699  * @name: the name of the action to remove
14700  *
14701  * Removes the #ClutterAction with the given name from the list
14702  * of actions applied to @self
14703  *
14704  * Since: 1.4
14705  */
14706 void
14707 clutter_actor_remove_action_by_name (ClutterActor *self,
14708                                      const gchar  *name)
14709 {
14710   ClutterActorPrivate *priv;
14711   ClutterActorMeta *meta;
14712
14713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14714   g_return_if_fail (name != NULL);
14715
14716   priv = self->priv;
14717
14718   if (priv->actions == NULL)
14719     return;
14720
14721   meta = _clutter_meta_group_get_meta (priv->actions, name);
14722   if (meta == NULL)
14723     return;
14724
14725   _clutter_meta_group_remove_meta (priv->actions, meta);
14726
14727   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14728 }
14729
14730 /**
14731  * clutter_actor_get_actions:
14732  * @self: a #ClutterActor
14733  *
14734  * Retrieves the list of actions applied to @self
14735  *
14736  * Return value: (transfer container) (element-type Clutter.Action): a copy
14737  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14738  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14739  *   allocated by the returned #GList
14740  *
14741  * Since: 1.4
14742  */
14743 GList *
14744 clutter_actor_get_actions (ClutterActor *self)
14745 {
14746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14747
14748   if (self->priv->actions == NULL)
14749     return NULL;
14750
14751   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14752 }
14753
14754 /**
14755  * clutter_actor_get_action:
14756  * @self: a #ClutterActor
14757  * @name: the name of the action to retrieve
14758  *
14759  * Retrieves the #ClutterAction with the given name in the list
14760  * of actions applied to @self
14761  *
14762  * Return value: (transfer none): a #ClutterAction for the given
14763  *   name, or %NULL. The returned #ClutterAction is owned by the
14764  *   actor and it should not be unreferenced directly
14765  *
14766  * Since: 1.4
14767  */
14768 ClutterAction *
14769 clutter_actor_get_action (ClutterActor *self,
14770                           const gchar  *name)
14771 {
14772   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14773   g_return_val_if_fail (name != NULL, NULL);
14774
14775   if (self->priv->actions == NULL)
14776     return NULL;
14777
14778   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14779 }
14780
14781 /**
14782  * clutter_actor_clear_actions:
14783  * @self: a #ClutterActor
14784  *
14785  * Clears the list of actions applied to @self
14786  *
14787  * Since: 1.4
14788  */
14789 void
14790 clutter_actor_clear_actions (ClutterActor *self)
14791 {
14792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14793
14794   if (self->priv->actions == NULL)
14795     return;
14796
14797   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14798 }
14799
14800 /**
14801  * clutter_actor_add_constraint:
14802  * @self: a #ClutterActor
14803  * @constraint: a #ClutterConstraint
14804  *
14805  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14806  * to @self
14807  *
14808  * The #ClutterActor will hold a reference on the @constraint until
14809  * either clutter_actor_remove_constraint() or
14810  * clutter_actor_clear_constraints() is called.
14811  *
14812  * Since: 1.4
14813  */
14814 void
14815 clutter_actor_add_constraint (ClutterActor      *self,
14816                               ClutterConstraint *constraint)
14817 {
14818   ClutterActorPrivate *priv;
14819
14820   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14821   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14822
14823   priv = self->priv;
14824
14825   if (priv->constraints == NULL)
14826     {
14827       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14828       priv->constraints->actor = self;
14829     }
14830
14831   _clutter_meta_group_add_meta (priv->constraints,
14832                                 CLUTTER_ACTOR_META (constraint));
14833   clutter_actor_queue_relayout (self);
14834
14835   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14836 }
14837
14838 /**
14839  * clutter_actor_add_constraint_with_name:
14840  * @self: a #ClutterActor
14841  * @name: the name to set on the constraint
14842  * @constraint: a #ClutterConstraint
14843  *
14844  * A convenience function for setting the name of a #ClutterConstraint
14845  * while adding it to the list of constraints applied to @self
14846  *
14847  * This function is the logical equivalent of:
14848  *
14849  * |[
14850  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14851  *   clutter_actor_add_constraint (self, constraint);
14852  * ]|
14853  *
14854  * Since: 1.4
14855  */
14856 void
14857 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14858                                         const gchar       *name,
14859                                         ClutterConstraint *constraint)
14860 {
14861   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14862   g_return_if_fail (name != NULL);
14863   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14864
14865   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14866   clutter_actor_add_constraint (self, constraint);
14867 }
14868
14869 /**
14870  * clutter_actor_remove_constraint:
14871  * @self: a #ClutterActor
14872  * @constraint: a #ClutterConstraint
14873  *
14874  * Removes @constraint from the list of constraints applied to @self
14875  *
14876  * The reference held by @self on the #ClutterConstraint will be released
14877  *
14878  * Since: 1.4
14879  */
14880 void
14881 clutter_actor_remove_constraint (ClutterActor      *self,
14882                                  ClutterConstraint *constraint)
14883 {
14884   ClutterActorPrivate *priv;
14885
14886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14887   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14888
14889   priv = self->priv;
14890
14891   if (priv->constraints == NULL)
14892     return;
14893
14894   _clutter_meta_group_remove_meta (priv->constraints,
14895                                    CLUTTER_ACTOR_META (constraint));
14896   clutter_actor_queue_relayout (self);
14897
14898   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14899 }
14900
14901 /**
14902  * clutter_actor_remove_constraint_by_name:
14903  * @self: a #ClutterActor
14904  * @name: the name of the constraint to remove
14905  *
14906  * Removes the #ClutterConstraint with the given name from the list
14907  * of constraints applied to @self
14908  *
14909  * Since: 1.4
14910  */
14911 void
14912 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14913                                          const gchar  *name)
14914 {
14915   ClutterActorPrivate *priv;
14916   ClutterActorMeta *meta;
14917
14918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14919   g_return_if_fail (name != NULL);
14920
14921   priv = self->priv;
14922
14923   if (priv->constraints == NULL)
14924     return;
14925
14926   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14927   if (meta == NULL)
14928     return;
14929
14930   _clutter_meta_group_remove_meta (priv->constraints, meta);
14931   clutter_actor_queue_relayout (self);
14932 }
14933
14934 /**
14935  * clutter_actor_get_constraints:
14936  * @self: a #ClutterActor
14937  *
14938  * Retrieves the list of constraints applied to @self
14939  *
14940  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14941  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14942  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14943  *   allocated by the returned #GList
14944  *
14945  * Since: 1.4
14946  */
14947 GList *
14948 clutter_actor_get_constraints (ClutterActor *self)
14949 {
14950   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14951
14952   if (self->priv->constraints == NULL)
14953     return NULL;
14954
14955   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14956 }
14957
14958 /**
14959  * clutter_actor_get_constraint:
14960  * @self: a #ClutterActor
14961  * @name: the name of the constraint to retrieve
14962  *
14963  * Retrieves the #ClutterConstraint with the given name in the list
14964  * of constraints applied to @self
14965  *
14966  * Return value: (transfer none): a #ClutterConstraint for the given
14967  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14968  *   actor and it should not be unreferenced directly
14969  *
14970  * Since: 1.4
14971  */
14972 ClutterConstraint *
14973 clutter_actor_get_constraint (ClutterActor *self,
14974                               const gchar  *name)
14975 {
14976   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14977   g_return_val_if_fail (name != NULL, NULL);
14978
14979   if (self->priv->constraints == NULL)
14980     return NULL;
14981
14982   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14983 }
14984
14985 /**
14986  * clutter_actor_clear_constraints:
14987  * @self: a #ClutterActor
14988  *
14989  * Clears the list of constraints applied to @self
14990  *
14991  * Since: 1.4
14992  */
14993 void
14994 clutter_actor_clear_constraints (ClutterActor *self)
14995 {
14996   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14997
14998   if (self->priv->constraints == NULL)
14999     return;
15000
15001   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15002
15003   clutter_actor_queue_relayout (self);
15004 }
15005
15006 /**
15007  * clutter_actor_set_clip_to_allocation:
15008  * @self: a #ClutterActor
15009  * @clip_set: %TRUE to apply a clip tracking the allocation
15010  *
15011  * Sets whether @self should be clipped to the same size as its
15012  * allocation
15013  *
15014  * Since: 1.4
15015  */
15016 void
15017 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15018                                       gboolean      clip_set)
15019 {
15020   ClutterActorPrivate *priv;
15021
15022   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15023
15024   clip_set = !!clip_set;
15025
15026   priv = self->priv;
15027
15028   if (priv->clip_to_allocation != clip_set)
15029     {
15030       priv->clip_to_allocation = clip_set;
15031
15032       clutter_actor_queue_redraw (self);
15033
15034       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15035     }
15036 }
15037
15038 /**
15039  * clutter_actor_get_clip_to_allocation:
15040  * @self: a #ClutterActor
15041  *
15042  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15043  *
15044  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15045  *
15046  * Since: 1.4
15047  */
15048 gboolean
15049 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15050 {
15051   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15052
15053   return self->priv->clip_to_allocation;
15054 }
15055
15056 /**
15057  * clutter_actor_add_effect:
15058  * @self: a #ClutterActor
15059  * @effect: a #ClutterEffect
15060  *
15061  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15062  *
15063  * The #ClutterActor will hold a reference on the @effect until either
15064  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15065  * called.
15066  *
15067  * Since: 1.4
15068  */
15069 void
15070 clutter_actor_add_effect (ClutterActor  *self,
15071                           ClutterEffect *effect)
15072 {
15073   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15074   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15075
15076   _clutter_actor_add_effect_internal (self, effect);
15077
15078   clutter_actor_queue_redraw (self);
15079
15080   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15081 }
15082
15083 /**
15084  * clutter_actor_add_effect_with_name:
15085  * @self: a #ClutterActor
15086  * @name: the name to set on the effect
15087  * @effect: a #ClutterEffect
15088  *
15089  * A convenience function for setting the name of a #ClutterEffect
15090  * while adding it to the list of effectss applied to @self
15091  *
15092  * This function is the logical equivalent of:
15093  *
15094  * |[
15095  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15096  *   clutter_actor_add_effect (self, effect);
15097  * ]|
15098  *
15099  * Since: 1.4
15100  */
15101 void
15102 clutter_actor_add_effect_with_name (ClutterActor  *self,
15103                                     const gchar   *name,
15104                                     ClutterEffect *effect)
15105 {
15106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15107   g_return_if_fail (name != NULL);
15108   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15109
15110   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15111   clutter_actor_add_effect (self, effect);
15112 }
15113
15114 /**
15115  * clutter_actor_remove_effect:
15116  * @self: a #ClutterActor
15117  * @effect: a #ClutterEffect
15118  *
15119  * Removes @effect from the list of effects applied to @self
15120  *
15121  * The reference held by @self on the #ClutterEffect will be released
15122  *
15123  * Since: 1.4
15124  */
15125 void
15126 clutter_actor_remove_effect (ClutterActor  *self,
15127                              ClutterEffect *effect)
15128 {
15129   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15130   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15131
15132   _clutter_actor_remove_effect_internal (self, effect);
15133
15134   clutter_actor_queue_redraw (self);
15135
15136   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15137 }
15138
15139 /**
15140  * clutter_actor_remove_effect_by_name:
15141  * @self: a #ClutterActor
15142  * @name: the name of the effect to remove
15143  *
15144  * Removes the #ClutterEffect with the given name from the list
15145  * of effects applied to @self
15146  *
15147  * Since: 1.4
15148  */
15149 void
15150 clutter_actor_remove_effect_by_name (ClutterActor *self,
15151                                      const gchar  *name)
15152 {
15153   ClutterActorPrivate *priv;
15154   ClutterActorMeta *meta;
15155
15156   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15157   g_return_if_fail (name != NULL);
15158
15159   priv = self->priv;
15160
15161   if (priv->effects == NULL)
15162     return;
15163
15164   meta = _clutter_meta_group_get_meta (priv->effects, name);
15165   if (meta == NULL)
15166     return;
15167
15168   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15169 }
15170
15171 /**
15172  * clutter_actor_get_effects:
15173  * @self: a #ClutterActor
15174  *
15175  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15176  *
15177  * Return value: (transfer container) (element-type Clutter.Effect): a list
15178  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15179  *   list are owned by Clutter and they should not be freed. You should
15180  *   free the returned list using g_list_free() when done
15181  *
15182  * Since: 1.4
15183  */
15184 GList *
15185 clutter_actor_get_effects (ClutterActor *self)
15186 {
15187   ClutterActorPrivate *priv;
15188
15189   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15190
15191   priv = self->priv;
15192
15193   if (priv->effects == NULL)
15194     return NULL;
15195
15196   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15197 }
15198
15199 /**
15200  * clutter_actor_get_effect:
15201  * @self: a #ClutterActor
15202  * @name: the name of the effect to retrieve
15203  *
15204  * Retrieves the #ClutterEffect with the given name in the list
15205  * of effects applied to @self
15206  *
15207  * Return value: (transfer none): a #ClutterEffect for the given
15208  *   name, or %NULL. The returned #ClutterEffect is owned by the
15209  *   actor and it should not be unreferenced directly
15210  *
15211  * Since: 1.4
15212  */
15213 ClutterEffect *
15214 clutter_actor_get_effect (ClutterActor *self,
15215                           const gchar  *name)
15216 {
15217   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15218   g_return_val_if_fail (name != NULL, NULL);
15219
15220   if (self->priv->effects == NULL)
15221     return NULL;
15222
15223   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15224 }
15225
15226 /**
15227  * clutter_actor_clear_effects:
15228  * @self: a #ClutterActor
15229  *
15230  * Clears the list of effects applied to @self
15231  *
15232  * Since: 1.4
15233  */
15234 void
15235 clutter_actor_clear_effects (ClutterActor *self)
15236 {
15237   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15238
15239   if (self->priv->effects == NULL)
15240     return;
15241
15242   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15243
15244   clutter_actor_queue_redraw (self);
15245 }
15246
15247 /**
15248  * clutter_actor_has_key_focus:
15249  * @self: a #ClutterActor
15250  *
15251  * Checks whether @self is the #ClutterActor that has key focus
15252  *
15253  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15254  *
15255  * Since: 1.4
15256  */
15257 gboolean
15258 clutter_actor_has_key_focus (ClutterActor *self)
15259 {
15260   ClutterActor *stage;
15261
15262   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15263
15264   stage = _clutter_actor_get_stage_internal (self);
15265   if (stage == NULL)
15266     return FALSE;
15267
15268   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15269 }
15270
15271 static gboolean
15272 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15273                                       ClutterPaintVolume *pv)
15274 {
15275   ClutterActorPrivate *priv = self->priv;
15276
15277   /* Actors are only expected to report a valid paint volume
15278    * while they have a valid allocation. */
15279   if (G_UNLIKELY (priv->needs_allocation))
15280     {
15281       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15282                     "Actor needs allocation",
15283                     _clutter_actor_get_debug_name (self));
15284       return FALSE;
15285     }
15286
15287   /* Check if there are any handlers connected to the paint
15288    * signal. If there are then all bets are off for what the paint
15289    * volume for this actor might possibly be!
15290    *
15291    * XXX: It's expected that this is going to end up being quite a
15292    * costly check to have to do here, but we haven't come up with
15293    * another solution that can reliably catch paint signal handlers at
15294    * the right time to either avoid artefacts due to invalid stage
15295    * clipping or due to incorrect culling.
15296    *
15297    * Previously we checked in clutter_actor_paint(), but at that time
15298    * we may already be using a stage clip that could be derived from
15299    * an invalid paint-volume. We used to try and handle that by
15300    * queuing a follow up, unclipped, redraw but still the previous
15301    * checking wasn't enough to catch invalid volumes involved in
15302    * culling (considering that containers may derive their volume from
15303    * children that haven't yet been painted)
15304    *
15305    * Longer term, improved solutions could be:
15306    * - Disallow painting in the paint signal, only allow using it
15307    *   for tracking when paints happen. We can add another API that
15308    *   allows monkey patching the paint of arbitrary actors but in a
15309    *   more controlled way and that also supports modifying the
15310    *   paint-volume.
15311    * - If we could be notified somehow when signal handlers are
15312    *   connected we wouldn't have to poll for handlers like this.
15313    */
15314   if (g_signal_has_handler_pending (self,
15315                                     actor_signals[PAINT],
15316                                     0,
15317                                     TRUE))
15318     {
15319       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15320                     "Actor has \"paint\" signal handlers",
15321                     _clutter_actor_get_debug_name (self));
15322       return FALSE;
15323     }
15324
15325   _clutter_paint_volume_init_static (pv, self);
15326
15327   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15328     {
15329       clutter_paint_volume_free (pv);
15330       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15331                     "Actor failed to report a volume",
15332                     _clutter_actor_get_debug_name (self));
15333       return FALSE;
15334     }
15335
15336   /* since effects can modify the paint volume, we allow them to actually
15337    * do this by making get_paint_volume() "context sensitive"
15338    */
15339   if (priv->effects != NULL)
15340     {
15341       if (priv->current_effect != NULL)
15342         {
15343           const GList *effects, *l;
15344
15345           /* if we are being called from within the paint sequence of
15346            * an actor, get the paint volume up to the current effect
15347            */
15348           effects = _clutter_meta_group_peek_metas (priv->effects);
15349           for (l = effects;
15350                l != NULL || (l != NULL && l->data != priv->current_effect);
15351                l = l->next)
15352             {
15353               if (!_clutter_effect_get_paint_volume (l->data, pv))
15354                 {
15355                   clutter_paint_volume_free (pv);
15356                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15357                                 "Effect (%s) failed to report a volume",
15358                                 _clutter_actor_get_debug_name (self),
15359                                 _clutter_actor_meta_get_debug_name (l->data));
15360                   return FALSE;
15361                 }
15362             }
15363         }
15364       else
15365         {
15366           const GList *effects, *l;
15367
15368           /* otherwise, get the cumulative volume */
15369           effects = _clutter_meta_group_peek_metas (priv->effects);
15370           for (l = effects; l != NULL; l = l->next)
15371             if (!_clutter_effect_get_paint_volume (l->data, pv))
15372               {
15373                 clutter_paint_volume_free (pv);
15374                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15375                               "Effect (%s) failed to report a volume",
15376                               _clutter_actor_get_debug_name (self),
15377                               _clutter_actor_meta_get_debug_name (l->data));
15378                 return FALSE;
15379               }
15380         }
15381     }
15382
15383   return TRUE;
15384 }
15385
15386 /* The public clutter_actor_get_paint_volume API returns a const
15387  * pointer since we return a pointer directly to the cached
15388  * PaintVolume associated with the actor and don't want the user to
15389  * inadvertently modify it, but for internal uses we sometimes need
15390  * access to the same PaintVolume but need to apply some book-keeping
15391  * modifications to it so we don't want a const pointer.
15392  */
15393 static ClutterPaintVolume *
15394 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15395 {
15396   ClutterActorPrivate *priv;
15397
15398   priv = self->priv;
15399
15400   if (priv->paint_volume_valid)
15401     clutter_paint_volume_free (&priv->paint_volume);
15402
15403   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15404     {
15405       priv->paint_volume_valid = TRUE;
15406       return &priv->paint_volume;
15407     }
15408   else
15409     {
15410       priv->paint_volume_valid = FALSE;
15411       return NULL;
15412     }
15413 }
15414
15415 /**
15416  * clutter_actor_get_paint_volume:
15417  * @self: a #ClutterActor
15418  *
15419  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15420  * when a paint volume can't be determined.
15421  *
15422  * The paint volume is defined as the 3D space occupied by an actor
15423  * when being painted.
15424  *
15425  * This function will call the <function>get_paint_volume()</function>
15426  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15427  * should not usually care about overriding the default implementation,
15428  * unless they are, for instance: painting outside their allocation, or
15429  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15430  * 3D depth).
15431  *
15432  * <note>2D actors overriding <function>get_paint_volume()</function>
15433  * ensure their volume has a depth of 0. (This will be true so long as
15434  * you don't call clutter_paint_volume_set_depth().)</note>
15435  *
15436  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15437  *   or %NULL if no volume could be determined. The returned pointer
15438  *   is not guaranteed to be valid across multiple frames; if you want
15439  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15440  *
15441  * Since: 1.6
15442  */
15443 const ClutterPaintVolume *
15444 clutter_actor_get_paint_volume (ClutterActor *self)
15445 {
15446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15447
15448   return _clutter_actor_get_paint_volume_mutable (self);
15449 }
15450
15451 /**
15452  * clutter_actor_get_transformed_paint_volume:
15453  * @self: a #ClutterActor
15454  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15455  *    (or %NULL for the stage)
15456  *
15457  * Retrieves the 3D paint volume of an actor like
15458  * clutter_actor_get_paint_volume() does (Please refer to the
15459  * documentation of clutter_actor_get_paint_volume() for more
15460  * details.) and it additionally transforms the paint volume into the
15461  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15462  * is passed for @relative_to_ancestor)
15463  *
15464  * This can be used by containers that base their paint volume on
15465  * the volume of their children. Such containers can query the
15466  * transformed paint volume of all of its children and union them
15467  * together using clutter_paint_volume_union().
15468  *
15469  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15470  *   or %NULL if no volume could be determined. The returned pointer is
15471  *   not guaranteed to be valid across multiple frames; if you wish to
15472  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15473  *
15474  * Since: 1.6
15475  */
15476 const ClutterPaintVolume *
15477 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15478                                             ClutterActor *relative_to_ancestor)
15479 {
15480   const ClutterPaintVolume *volume;
15481   ClutterActor *stage;
15482   ClutterPaintVolume *transformed_volume;
15483
15484   stage = _clutter_actor_get_stage_internal (self);
15485   if (G_UNLIKELY (stage == NULL))
15486     return NULL;
15487
15488   if (relative_to_ancestor == NULL)
15489     relative_to_ancestor = stage;
15490
15491   volume = clutter_actor_get_paint_volume (self);
15492   if (volume == NULL)
15493     return NULL;
15494
15495   transformed_volume =
15496     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15497
15498   _clutter_paint_volume_copy_static (volume, transformed_volume);
15499
15500   _clutter_paint_volume_transform_relative (transformed_volume,
15501                                             relative_to_ancestor);
15502
15503   return transformed_volume;
15504 }
15505
15506 /**
15507  * clutter_actor_get_paint_box:
15508  * @self: a #ClutterActor
15509  * @box: (out): return location for a #ClutterActorBox
15510  *
15511  * Retrieves the paint volume of the passed #ClutterActor, and
15512  * transforms it into a 2D bounding box in stage coordinates.
15513  *
15514  * This function is useful to determine the on screen area occupied by
15515  * the actor. The box is only an approximation and may often be
15516  * considerably larger due to the optimizations used to calculate the
15517  * box. The box is never smaller though, so it can reliably be used
15518  * for culling.
15519  *
15520  * There are times when a 2D paint box can't be determined, e.g.
15521  * because the actor isn't yet parented under a stage or because
15522  * the actor is unable to determine a paint volume.
15523  *
15524  * Return value: %TRUE if a 2D paint box could be determined, else
15525  * %FALSE.
15526  *
15527  * Since: 1.6
15528  */
15529 gboolean
15530 clutter_actor_get_paint_box (ClutterActor    *self,
15531                              ClutterActorBox *box)
15532 {
15533   ClutterActor *stage;
15534   ClutterPaintVolume *pv;
15535
15536   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15537   g_return_val_if_fail (box != NULL, FALSE);
15538
15539   stage = _clutter_actor_get_stage_internal (self);
15540   if (G_UNLIKELY (!stage))
15541     return FALSE;
15542
15543   pv = _clutter_actor_get_paint_volume_mutable (self);
15544   if (G_UNLIKELY (!pv))
15545     return FALSE;
15546
15547   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15548
15549   return TRUE;
15550 }
15551
15552 /**
15553  * clutter_actor_has_overlaps:
15554  * @self: A #ClutterActor
15555  *
15556  * Asks the actor's implementation whether it may contain overlapping
15557  * primitives.
15558  *
15559  * For example; Clutter may use this to determine whether the painting
15560  * should be redirected to an offscreen buffer to correctly implement
15561  * the opacity property.
15562  *
15563  * Custom actors can override the default response by implementing the
15564  * #ClutterActor <function>has_overlaps</function> virtual function. See
15565  * clutter_actor_set_offscreen_redirect() for more information.
15566  *
15567  * Return value: %TRUE if the actor may have overlapping primitives, and
15568  *   %FALSE otherwise
15569  *
15570  * Since: 1.8
15571  */
15572 gboolean
15573 clutter_actor_has_overlaps (ClutterActor *self)
15574 {
15575   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15576
15577   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15578 }
15579
15580 /**
15581  * clutter_actor_has_effects:
15582  * @self: A #ClutterActor
15583  *
15584  * Returns whether the actor has any effects applied.
15585  *
15586  * Return value: %TRUE if the actor has any effects,
15587  *   %FALSE otherwise
15588  *
15589  * Since: 1.10
15590  */
15591 gboolean
15592 clutter_actor_has_effects (ClutterActor *self)
15593 {
15594   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15595
15596   if (self->priv->effects == NULL)
15597     return FALSE;
15598
15599   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15600 }
15601
15602 /**
15603  * clutter_actor_has_constraints:
15604  * @self: A #ClutterActor
15605  *
15606  * Returns whether the actor has any constraints applied.
15607  *
15608  * Return value: %TRUE if the actor has any constraints,
15609  *   %FALSE otherwise
15610  *
15611  * Since: 1.10
15612  */
15613 gboolean
15614 clutter_actor_has_constraints (ClutterActor *self)
15615 {
15616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15617
15618   return self->priv->constraints != NULL;
15619 }
15620
15621 /**
15622  * clutter_actor_has_actions:
15623  * @self: A #ClutterActor
15624  *
15625  * Returns whether the actor has any actions applied.
15626  *
15627  * Return value: %TRUE if the actor has any actions,
15628  *   %FALSE otherwise
15629  *
15630  * Since: 1.10
15631  */
15632 gboolean
15633 clutter_actor_has_actions (ClutterActor *self)
15634 {
15635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15636
15637   return self->priv->actions != NULL;
15638 }
15639
15640 /**
15641  * clutter_actor_get_n_children:
15642  * @self: a #ClutterActor
15643  *
15644  * Retrieves the number of children of @self.
15645  *
15646  * Return value: the number of children of an actor
15647  *
15648  * Since: 1.10
15649  */
15650 gint
15651 clutter_actor_get_n_children (ClutterActor *self)
15652 {
15653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15654
15655   return self->priv->n_children;
15656 }
15657
15658 /**
15659  * clutter_actor_get_child_at_index:
15660  * @self: a #ClutterActor
15661  * @index_: the position in the list of children
15662  *
15663  * Retrieves the actor at the given @index_ inside the list of
15664  * children of @self.
15665  *
15666  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15667  *
15668  * Since: 1.10
15669  */
15670 ClutterActor *
15671 clutter_actor_get_child_at_index (ClutterActor *self,
15672                                   gint          index_)
15673 {
15674   ClutterActor *iter;
15675   int i;
15676
15677   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15678   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15679
15680   for (iter = self->priv->first_child, i = 0;
15681        iter != NULL && i < index_;
15682        iter = iter->priv->next_sibling, i += 1)
15683     ;
15684
15685   return iter;
15686 }
15687
15688 /*< private >
15689  * _clutter_actor_foreach_child:
15690  * @actor: The actor whos children you want to iterate
15691  * @callback: The function to call for each child
15692  * @user_data: Private data to pass to @callback
15693  *
15694  * Calls a given @callback once for each child of the specified @actor and
15695  * passing the @user_data pointer each time.
15696  *
15697  * Return value: returns %TRUE if all children were iterated, else
15698  *    %FALSE if a callback broke out of iteration early.
15699  */
15700 gboolean
15701 _clutter_actor_foreach_child (ClutterActor           *self,
15702                               ClutterForeachCallback  callback,
15703                               gpointer                user_data)
15704 {
15705   ClutterActorPrivate *priv = self->priv;
15706   ClutterActor *iter;
15707   gboolean cont;
15708
15709   for (cont = TRUE, iter = priv->first_child;
15710        cont && iter != NULL;
15711        iter = iter->priv->next_sibling)
15712     {
15713       cont = callback (iter, user_data);
15714     }
15715
15716   return cont;
15717 }
15718
15719 #if 0
15720 /* For debugging purposes this gives us a simple way to print out
15721  * the scenegraph e.g in gdb using:
15722  * [|
15723  *   _clutter_actor_traverse (stage,
15724  *                            0,
15725  *                            clutter_debug_print_actor_cb,
15726  *                            NULL,
15727  *                            NULL);
15728  * |]
15729  */
15730 static ClutterActorTraverseVisitFlags
15731 clutter_debug_print_actor_cb (ClutterActor *actor,
15732                               int depth,
15733                               void *user_data)
15734 {
15735   g_print ("%*s%s:%p\n",
15736            depth * 2, "",
15737            _clutter_actor_get_debug_name (actor),
15738            actor);
15739
15740   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15741 }
15742 #endif
15743
15744 static void
15745 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15746                                  ClutterTraverseCallback callback,
15747                                  gpointer                user_data)
15748 {
15749   GQueue *queue = g_queue_new ();
15750   ClutterActor dummy;
15751   int current_depth = 0;
15752
15753   g_queue_push_tail (queue, actor);
15754   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15755
15756   while ((actor = g_queue_pop_head (queue)))
15757     {
15758       ClutterActorTraverseVisitFlags flags;
15759
15760       if (actor == &dummy)
15761         {
15762           current_depth++;
15763           g_queue_push_tail (queue, &dummy);
15764           continue;
15765         }
15766
15767       flags = callback (actor, current_depth, user_data);
15768       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15769         break;
15770       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15771         {
15772           ClutterActor *iter;
15773
15774           for (iter = actor->priv->first_child;
15775                iter != NULL;
15776                iter = iter->priv->next_sibling)
15777             {
15778               g_queue_push_tail (queue, iter);
15779             }
15780         }
15781     }
15782
15783   g_queue_free (queue);
15784 }
15785
15786 static ClutterActorTraverseVisitFlags
15787 _clutter_actor_traverse_depth (ClutterActor           *actor,
15788                                ClutterTraverseCallback before_children_callback,
15789                                ClutterTraverseCallback after_children_callback,
15790                                int                     current_depth,
15791                                gpointer                user_data)
15792 {
15793   ClutterActorTraverseVisitFlags flags;
15794
15795   flags = before_children_callback (actor, current_depth, user_data);
15796   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15797     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15798
15799   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15800     {
15801       ClutterActor *iter;
15802
15803       for (iter = actor->priv->first_child;
15804            iter != NULL;
15805            iter = iter->priv->next_sibling)
15806         {
15807           flags = _clutter_actor_traverse_depth (iter,
15808                                                  before_children_callback,
15809                                                  after_children_callback,
15810                                                  current_depth + 1,
15811                                                  user_data);
15812
15813           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15814             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15815         }
15816     }
15817
15818   if (after_children_callback)
15819     return after_children_callback (actor, current_depth, user_data);
15820   else
15821     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15822 }
15823
15824 /* _clutter_actor_traverse:
15825  * @actor: The actor to start traversing the graph from
15826  * @flags: These flags may affect how the traversal is done
15827  * @before_children_callback: A function to call before visiting the
15828  *   children of the current actor.
15829  * @after_children_callback: A function to call after visiting the
15830  *   children of the current actor. (Ignored if
15831  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15832  * @user_data: The private data to pass to the callbacks
15833  *
15834  * Traverses the scenegraph starting at the specified @actor and
15835  * descending through all its children and its children's children.
15836  * For each actor traversed @before_children_callback and
15837  * @after_children_callback are called with the specified
15838  * @user_data, before and after visiting that actor's children.
15839  *
15840  * The callbacks can return flags that affect the ongoing traversal
15841  * such as by skipping over an actors children or bailing out of
15842  * any further traversing.
15843  */
15844 void
15845 _clutter_actor_traverse (ClutterActor              *actor,
15846                          ClutterActorTraverseFlags  flags,
15847                          ClutterTraverseCallback    before_children_callback,
15848                          ClutterTraverseCallback    after_children_callback,
15849                          gpointer                   user_data)
15850 {
15851   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15852     _clutter_actor_traverse_breadth (actor,
15853                                      before_children_callback,
15854                                      user_data);
15855   else /* DEPTH_FIRST */
15856     _clutter_actor_traverse_depth (actor,
15857                                    before_children_callback,
15858                                    after_children_callback,
15859                                    0, /* start depth */
15860                                    user_data);
15861 }
15862
15863 static void
15864 on_layout_manager_changed (ClutterLayoutManager *manager,
15865                            ClutterActor         *self)
15866 {
15867   clutter_actor_queue_relayout (self);
15868 }
15869
15870 /**
15871  * clutter_actor_set_layout_manager:
15872  * @self: a #ClutterActor
15873  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15874  *
15875  * Sets the #ClutterLayoutManager delegate object that will be used to
15876  * lay out the children of @self.
15877  *
15878  * The #ClutterActor will take a reference on the passed @manager which
15879  * will be released either when the layout manager is removed, or when
15880  * the actor is destroyed.
15881  *
15882  * Since: 1.10
15883  */
15884 void
15885 clutter_actor_set_layout_manager (ClutterActor         *self,
15886                                   ClutterLayoutManager *manager)
15887 {
15888   ClutterActorPrivate *priv;
15889
15890   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15891   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15892
15893   priv = self->priv;
15894
15895   if (priv->layout_manager != NULL)
15896     {
15897       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15898                                             G_CALLBACK (on_layout_manager_changed),
15899                                             self);
15900       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15901       g_object_unref (priv->layout_manager);
15902     }
15903
15904   priv->layout_manager = manager;
15905
15906   if (priv->layout_manager != NULL)
15907     {
15908       g_object_ref_sink (priv->layout_manager);
15909       clutter_layout_manager_set_container (priv->layout_manager,
15910                                             CLUTTER_CONTAINER (self));
15911       g_signal_connect (priv->layout_manager, "layout-changed",
15912                         G_CALLBACK (on_layout_manager_changed),
15913                         self);
15914     }
15915
15916   clutter_actor_queue_relayout (self);
15917
15918   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15919 }
15920
15921 /**
15922  * clutter_actor_get_layout_manager:
15923  * @self: a #ClutterActor
15924  *
15925  * Retrieves the #ClutterLayoutManager used by @self.
15926  *
15927  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15928  *   or %NULL
15929  *
15930  * Since: 1.10
15931  */
15932 ClutterLayoutManager *
15933 clutter_actor_get_layout_manager (ClutterActor *self)
15934 {
15935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15936
15937   return self->priv->layout_manager;
15938 }
15939
15940 static const ClutterLayoutInfo default_layout_info = {
15941   0.f,                          /* fixed-x */
15942   0.f,                          /* fixed-y */
15943   { 0, 0, 0, 0 },               /* margin */
15944   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15945   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15946   0.f, 0.f,                     /* min_width, natural_width */
15947   0.f, 0.f,                     /* natual_width, natural_height */
15948 };
15949
15950 static void
15951 layout_info_free (gpointer data)
15952 {
15953   if (G_LIKELY (data != NULL))
15954     g_slice_free (ClutterLayoutInfo, data);
15955 }
15956
15957 /*< private >
15958  * _clutter_actor_get_layout_info:
15959  * @self: a #ClutterActor
15960  *
15961  * Retrieves a pointer to the ClutterLayoutInfo structure.
15962  *
15963  * If the actor does not have a ClutterLayoutInfo associated to it, one
15964  * will be created and initialized to the default values.
15965  *
15966  * This function should be used for setters.
15967  *
15968  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15969  * instead.
15970  *
15971  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15972  */
15973 ClutterLayoutInfo *
15974 _clutter_actor_get_layout_info (ClutterActor *self)
15975 {
15976   ClutterLayoutInfo *retval;
15977
15978   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15979   if (retval == NULL)
15980     {
15981       retval = g_slice_new (ClutterLayoutInfo);
15982
15983       *retval = default_layout_info;
15984
15985       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15986                                retval,
15987                                layout_info_free);
15988     }
15989
15990   return retval;
15991 }
15992
15993 /*< private >
15994  * _clutter_actor_get_layout_info_or_defaults:
15995  * @self: a #ClutterActor
15996  *
15997  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15998  *
15999  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16000  * then the default structure will be returned.
16001  *
16002  * This function should only be used for getters.
16003  *
16004  * Return value: a const pointer to the ClutterLayoutInfo structure
16005  */
16006 const ClutterLayoutInfo *
16007 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16008 {
16009   const ClutterLayoutInfo *info;
16010
16011   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16012   if (info == NULL)
16013     return &default_layout_info;
16014
16015   return info;
16016 }
16017
16018 /**
16019  * clutter_actor_set_x_align:
16020  * @self: a #ClutterActor
16021  * @x_align: the horizontal alignment policy
16022  *
16023  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16024  * actor received extra horizontal space.
16025  *
16026  * See also the #ClutterActor:x-align property.
16027  *
16028  * Since: 1.10
16029  */
16030 void
16031 clutter_actor_set_x_align (ClutterActor      *self,
16032                            ClutterActorAlign  x_align)
16033 {
16034   ClutterLayoutInfo *info;
16035
16036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16037
16038   info = _clutter_actor_get_layout_info (self);
16039
16040   if (info->x_align != x_align)
16041     {
16042       info->x_align = x_align;
16043
16044       clutter_actor_queue_relayout (self);
16045
16046       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16047     }
16048 }
16049
16050 /**
16051  * clutter_actor_get_x_align:
16052  * @self: a #ClutterActor
16053  *
16054  * Retrieves the horizontal alignment policy set using
16055  * clutter_actor_set_x_align().
16056  *
16057  * Return value: the horizontal alignment policy.
16058  *
16059  * Since: 1.10
16060  */
16061 ClutterActorAlign
16062 clutter_actor_get_x_align (ClutterActor *self)
16063 {
16064   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16065
16066   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16067 }
16068
16069 /**
16070  * clutter_actor_set_y_align:
16071  * @self: a #ClutterActor
16072  * @y_align: the vertical alignment policy
16073  *
16074  * Sets the vertical alignment policy of a #ClutterActor, in case the
16075  * actor received extra vertical space.
16076  *
16077  * See also the #ClutterActor:y-align property.
16078  *
16079  * Since: 1.10
16080  */
16081 void
16082 clutter_actor_set_y_align (ClutterActor      *self,
16083                            ClutterActorAlign  y_align)
16084 {
16085   ClutterLayoutInfo *info;
16086
16087   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16088
16089   info = _clutter_actor_get_layout_info (self);
16090
16091   if (info->y_align != y_align)
16092     {
16093       info->y_align = y_align;
16094
16095       clutter_actor_queue_relayout (self);
16096
16097       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16098     }
16099 }
16100
16101 /**
16102  * clutter_actor_get_y_align:
16103  * @self: a #ClutterActor
16104  *
16105  * Retrieves the vertical alignment policy set using
16106  * clutter_actor_set_y_align().
16107  *
16108  * Return value: the vertical alignment policy.
16109  *
16110  * Since: 1.10
16111  */
16112 ClutterActorAlign
16113 clutter_actor_get_y_align (ClutterActor *self)
16114 {
16115   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16116
16117   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16118 }
16119
16120
16121 /**
16122  * clutter_margin_new:
16123  *
16124  * Creates a new #ClutterMargin.
16125  *
16126  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16127  *   clutter_margin_free() to free the resources associated with it when
16128  *   done.
16129  *
16130  * Since: 1.10
16131  */
16132 ClutterMargin *
16133 clutter_margin_new (void)
16134 {
16135   return g_slice_new0 (ClutterMargin);
16136 }
16137
16138 /**
16139  * clutter_margin_copy:
16140  * @margin_: a #ClutterMargin
16141  *
16142  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16143  * the newly created structure.
16144  *
16145  * Return value: (transfer full): a copy of the #ClutterMargin.
16146  *
16147  * Since: 1.10
16148  */
16149 ClutterMargin *
16150 clutter_margin_copy (const ClutterMargin *margin_)
16151 {
16152   if (G_LIKELY (margin_ != NULL))
16153     return g_slice_dup (ClutterMargin, margin_);
16154
16155   return NULL;
16156 }
16157
16158 /**
16159  * clutter_margin_free:
16160  * @margin_: a #ClutterMargin
16161  *
16162  * Frees the resources allocated by clutter_margin_new() and
16163  * clutter_margin_copy().
16164  *
16165  * Since: 1.10
16166  */
16167 void
16168 clutter_margin_free (ClutterMargin *margin_)
16169 {
16170   if (G_LIKELY (margin_ != NULL))
16171     g_slice_free (ClutterMargin, margin_);
16172 }
16173
16174 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16175                      clutter_margin_copy,
16176                      clutter_margin_free)
16177
16178 /**
16179  * clutter_actor_set_margin:
16180  * @self: a #ClutterActor
16181  * @margin: a #ClutterMargin
16182  *
16183  * Sets all the components of the margin of a #ClutterActor.
16184  *
16185  * Since: 1.10
16186  */
16187 void
16188 clutter_actor_set_margin (ClutterActor        *self,
16189                           const ClutterMargin *margin)
16190 {
16191   ClutterLayoutInfo *info;
16192   gboolean changed;
16193   GObject *obj;
16194
16195   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16196   g_return_if_fail (margin != NULL);
16197
16198   obj = G_OBJECT (self);
16199   changed = FALSE;
16200
16201   g_object_freeze_notify (obj);
16202
16203   info = _clutter_actor_get_layout_info (self);
16204
16205   if (info->margin.top != margin->top)
16206     {
16207       info->margin.top = margin->top;
16208       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16209       changed = TRUE;
16210     }
16211
16212   if (info->margin.right != margin->right)
16213     {
16214       info->margin.right = margin->right;
16215       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16216       changed = TRUE;
16217     }
16218
16219   if (info->margin.bottom != margin->bottom)
16220     {
16221       info->margin.bottom = margin->bottom;
16222       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16223       changed = TRUE;
16224     }
16225
16226   if (info->margin.left != margin->left)
16227     {
16228       info->margin.left = margin->left;
16229       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16230       changed = TRUE;
16231     }
16232
16233   if (changed)
16234     clutter_actor_queue_relayout (self);
16235
16236   g_object_thaw_notify (obj);
16237 }
16238
16239 /**
16240  * clutter_actor_get_margin:
16241  * @self: a #ClutterActor
16242  * @margin: (out caller-allocates): return location for a #ClutterMargin
16243  *
16244  * Retrieves all the components of the margin of a #ClutterActor.
16245  *
16246  * Since: 1.10
16247  */
16248 void
16249 clutter_actor_get_margin (ClutterActor  *self,
16250                           ClutterMargin *margin)
16251 {
16252   const ClutterLayoutInfo *info;
16253
16254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16255   g_return_if_fail (margin != NULL);
16256
16257   info = _clutter_actor_get_layout_info_or_defaults (self);
16258
16259   *margin = info->margin;
16260 }
16261
16262 /**
16263  * clutter_actor_set_margin_top:
16264  * @self: a #ClutterActor
16265  * @margin: the top margin
16266  *
16267  * Sets the margin from the top of a #ClutterActor.
16268  *
16269  * Since: 1.10
16270  */
16271 void
16272 clutter_actor_set_margin_top (ClutterActor *self,
16273                               gfloat        margin)
16274 {
16275   ClutterLayoutInfo *info;
16276
16277   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16278   g_return_if_fail (margin >= 0.f);
16279
16280   info = _clutter_actor_get_layout_info (self);
16281
16282   if (info->margin.top == margin)
16283     return;
16284
16285   info->margin.top = margin;
16286
16287   clutter_actor_queue_relayout (self);
16288
16289   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16290 }
16291
16292 /**
16293  * clutter_actor_get_margin_top:
16294  * @self: a #ClutterActor
16295  *
16296  * Retrieves the top margin of a #ClutterActor.
16297  *
16298  * Return value: the top margin
16299  *
16300  * Since: 1.10
16301  */
16302 gfloat
16303 clutter_actor_get_margin_top (ClutterActor *self)
16304 {
16305   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16306
16307   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16308 }
16309
16310 /**
16311  * clutter_actor_set_margin_bottom:
16312  * @self: a #ClutterActor
16313  * @margin: the bottom margin
16314  *
16315  * Sets the margin from the bottom of a #ClutterActor.
16316  *
16317  * Since: 1.10
16318  */
16319 void
16320 clutter_actor_set_margin_bottom (ClutterActor *self,
16321                                  gfloat        margin)
16322 {
16323   ClutterLayoutInfo *info;
16324
16325   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16326   g_return_if_fail (margin >= 0.f);
16327
16328   info = _clutter_actor_get_layout_info (self);
16329
16330   if (info->margin.bottom == margin)
16331     return;
16332
16333   info->margin.bottom = margin;
16334
16335   clutter_actor_queue_relayout (self);
16336
16337   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16338 }
16339
16340 /**
16341  * clutter_actor_get_margin_bottom:
16342  * @self: a #ClutterActor
16343  *
16344  * Retrieves the bottom margin of a #ClutterActor.
16345  *
16346  * Return value: the bottom margin
16347  *
16348  * Since: 1.10
16349  */
16350 gfloat
16351 clutter_actor_get_margin_bottom (ClutterActor *self)
16352 {
16353   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16354
16355   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16356 }
16357
16358 /**
16359  * clutter_actor_set_margin_left:
16360  * @self: a #ClutterActor
16361  * @margin: the left margin
16362  *
16363  * Sets the margin from the left of a #ClutterActor.
16364  *
16365  * Since: 1.10
16366  */
16367 void
16368 clutter_actor_set_margin_left (ClutterActor *self,
16369                                gfloat        margin)
16370 {
16371   ClutterLayoutInfo *info;
16372
16373   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16374   g_return_if_fail (margin >= 0.f);
16375
16376   info = _clutter_actor_get_layout_info (self);
16377
16378   if (info->margin.left == margin)
16379     return;
16380
16381   info->margin.left = margin;
16382
16383   clutter_actor_queue_relayout (self);
16384
16385   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16386 }
16387
16388 /**
16389  * clutter_actor_get_margin_left:
16390  * @self: a #ClutterActor
16391  *
16392  * Retrieves the left margin of a #ClutterActor.
16393  *
16394  * Return value: the left margin
16395  *
16396  * Since: 1.10
16397  */
16398 gfloat
16399 clutter_actor_get_margin_left (ClutterActor *self)
16400 {
16401   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16402
16403   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16404 }
16405
16406 /**
16407  * clutter_actor_set_margin_right:
16408  * @self: a #ClutterActor
16409  * @margin: the right margin
16410  *
16411  * Sets the margin from the right of a #ClutterActor.
16412  *
16413  * Since: 1.10
16414  */
16415 void
16416 clutter_actor_set_margin_right (ClutterActor *self,
16417                                 gfloat        margin)
16418 {
16419   ClutterLayoutInfo *info;
16420
16421   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16422   g_return_if_fail (margin >= 0.f);
16423
16424   info = _clutter_actor_get_layout_info (self);
16425
16426   if (info->margin.right == margin)
16427     return;
16428
16429   info->margin.right = margin;
16430
16431   clutter_actor_queue_relayout (self);
16432
16433   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16434 }
16435
16436 /**
16437  * clutter_actor_get_margin_right:
16438  * @self: a #ClutterActor
16439  *
16440  * Retrieves the right margin of a #ClutterActor.
16441  *
16442  * Return value: the right margin
16443  *
16444  * Since: 1.10
16445  */
16446 gfloat
16447 clutter_actor_get_margin_right (ClutterActor *self)
16448 {
16449   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16450
16451   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16452 }
16453
16454 static inline void
16455 clutter_actor_set_background_color_internal (ClutterActor *self,
16456                                              const ClutterColor *color)
16457 {
16458   ClutterActorPrivate *priv = self->priv;
16459   GObject *obj;
16460
16461   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16462     return;
16463
16464   obj = G_OBJECT (self);
16465
16466   priv->bg_color = *color;
16467   priv->bg_color_set = TRUE;
16468
16469   clutter_actor_queue_redraw (self);
16470
16471   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16472   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16473 }
16474
16475 /**
16476  * clutter_actor_set_background_color:
16477  * @self: a #ClutterActor
16478  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16479  *  set color
16480  *
16481  * Sets the background color of a #ClutterActor.
16482  *
16483  * The background color will be used to cover the whole allocation of the
16484  * actor. The default background color of an actor is transparent.
16485  *
16486  * To check whether an actor has a background color, you can use the
16487  * #ClutterActor:background-color-set actor property.
16488  *
16489  * The #ClutterActor:background-color property is animatable.
16490  *
16491  * Since: 1.10
16492  */
16493 void
16494 clutter_actor_set_background_color (ClutterActor       *self,
16495                                     const ClutterColor *color)
16496 {
16497   ClutterActorPrivate *priv;
16498   GObject *obj;
16499   GParamSpec *bg_color_pspec;
16500
16501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16502
16503   obj = G_OBJECT (self);
16504
16505   priv = self->priv;
16506
16507   if (color == NULL)
16508     {
16509       priv->bg_color_set = FALSE;
16510       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16511       clutter_actor_queue_redraw (self);
16512       return;
16513     }
16514
16515   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16516   if (clutter_actor_get_easing_duration (self) != 0)
16517     {
16518       ClutterTransition *transition;
16519
16520       transition = _clutter_actor_get_transition (self, bg_color_pspec);
16521       if (transition == NULL)
16522         {
16523           transition = _clutter_actor_create_transition (self, bg_color_pspec,
16524                                                          &priv->bg_color,
16525                                                          color);
16526           clutter_timeline_start (CLUTTER_TIMELINE (transition));
16527         }
16528       else
16529         _clutter_actor_update_transition (self, bg_color_pspec, color);
16530
16531       clutter_actor_queue_redraw (self);
16532     }
16533   else
16534     clutter_actor_set_background_color_internal (self, color);
16535 }
16536
16537 /**
16538  * clutter_actor_get_background_color:
16539  * @self: a #ClutterActor
16540  * @color: (out caller-allocates): return location for a #ClutterColor
16541  *
16542  * Retrieves the color set using clutter_actor_set_background_color().
16543  *
16544  * Since: 1.10
16545  */
16546 void
16547 clutter_actor_get_background_color (ClutterActor *self,
16548                                     ClutterColor *color)
16549 {
16550   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16551   g_return_if_fail (color != NULL);
16552
16553   *color = self->priv->bg_color;
16554 }
16555
16556 /**
16557  * clutter_actor_get_previous_sibling:
16558  * @self: a #ClutterActor
16559  *
16560  * Retrieves the sibling of @self that comes before it in the list
16561  * of children of @self's parent.
16562  *
16563  * The returned pointer is only valid until the scene graph changes; it
16564  * is not safe to modify the list of children of @self while iterating
16565  * it.
16566  *
16567  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16568  *
16569  * Since: 1.10
16570  */
16571 ClutterActor *
16572 clutter_actor_get_previous_sibling (ClutterActor *self)
16573 {
16574   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16575
16576   return self->priv->prev_sibling;
16577 }
16578
16579 /**
16580  * clutter_actor_get_next_sibling:
16581  * @self: a #ClutterActor
16582  *
16583  * Retrieves the sibling of @self that comes after it in the list
16584  * of children of @self's parent.
16585  *
16586  * The returned pointer is only valid until the scene graph changes; it
16587  * is not safe to modify the list of children of @self while iterating
16588  * it.
16589  *
16590  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16591  *
16592  * Since: 1.10
16593  */
16594 ClutterActor *
16595 clutter_actor_get_next_sibling (ClutterActor *self)
16596 {
16597   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16598
16599   return self->priv->next_sibling;
16600 }
16601
16602 /**
16603  * clutter_actor_get_first_child:
16604  * @self: a #ClutterActor
16605  *
16606  * Retrieves the first child of @self.
16607  *
16608  * The returned pointer is only valid until the scene graph changes; it
16609  * is not safe to modify the list of children of @self while iterating
16610  * it.
16611  *
16612  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16613  *
16614  * Since: 1.10
16615  */
16616 ClutterActor *
16617 clutter_actor_get_first_child (ClutterActor *self)
16618 {
16619   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16620
16621   return self->priv->first_child;
16622 }
16623
16624 /**
16625  * clutter_actor_get_last_child:
16626  * @self: a #ClutterActor
16627  *
16628  * Retrieves the last child of @self.
16629  *
16630  * The returned pointer is only valid until the scene graph changes; it
16631  * is not safe to modify the list of children of @self while iterating
16632  * it.
16633  *
16634  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16635  *
16636  * Since: 1.10
16637  */
16638 ClutterActor *
16639 clutter_actor_get_last_child (ClutterActor *self)
16640 {
16641   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16642
16643   return self->priv->last_child;
16644 }
16645
16646 /* easy way to have properly named fields instead of the dummy ones
16647  * we use in the public structure
16648  */
16649 typedef struct _RealActorIter
16650 {
16651   ClutterActor *root;           /* dummy1 */
16652   ClutterActor *current;        /* dummy2 */
16653   gpointer padding_1;           /* dummy3 */
16654   gint age;                     /* dummy4 */
16655   gpointer padding_2;           /* dummy5 */
16656 } RealActorIter;
16657
16658 /**
16659  * clutter_actor_iter_init:
16660  * @iter: a #ClutterActorIter
16661  * @root: a #ClutterActor
16662  *
16663  * Initializes a #ClutterActorIter, which can then be used to iterate
16664  * efficiently over a section of the scene graph, and associates it
16665  * with @root.
16666  *
16667  * Modifying the scene graph section that contains @root will invalidate
16668  * the iterator.
16669  *
16670  * |[
16671  *   ClutterActorIter iter;
16672  *   ClutterActor *child;
16673  *
16674  *   clutter_actor_iter_init (&iter, container);
16675  *   while (clutter_actor_iter_next (&iter, &child))
16676  *     {
16677  *       /&ast; do something with child &ast;/
16678  *     }
16679  * ]|
16680  *
16681  * Since: 1.10
16682  */
16683 void
16684 clutter_actor_iter_init (ClutterActorIter *iter,
16685                          ClutterActor     *root)
16686 {
16687   RealActorIter *ri = (RealActorIter *) iter;
16688
16689   g_return_if_fail (iter != NULL);
16690   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16691
16692   ri->root = root;
16693   ri->current = NULL;
16694   ri->age = root->priv->age;
16695 }
16696
16697 /**
16698  * clutter_actor_iter_next:
16699  * @iter: a #ClutterActorIter
16700  * @child: (out): return location for a #ClutterActor
16701  *
16702  * Advances the @iter and retrieves the next child of the root #ClutterActor
16703  * that was used to initialize the #ClutterActorIterator.
16704  *
16705  * If the iterator can advance, this function returns %TRUE and sets the
16706  * @child argument.
16707  *
16708  * If the iterator cannot advance, this function returns %FALSE, and
16709  * the contents of @child are undefined.
16710  *
16711  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16712  *
16713  * Since: 1.10
16714  */
16715 gboolean
16716 clutter_actor_iter_next (ClutterActorIter  *iter,
16717                          ClutterActor     **child)
16718 {
16719   RealActorIter *ri = (RealActorIter *) iter;
16720
16721   g_return_val_if_fail (iter != NULL, FALSE);
16722   g_return_val_if_fail (ri->root != NULL, FALSE);
16723 #ifndef G_DISABLE_ASSERT
16724   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16725 #endif
16726
16727   if (ri->current == NULL)
16728     ri->current = ri->root->priv->first_child;
16729   else
16730     ri->current = ri->current->priv->next_sibling;
16731
16732   if (child != NULL)
16733     *child = ri->current;
16734
16735   return ri->current != NULL;
16736 }
16737
16738 /**
16739  * clutter_actor_iter_prev:
16740  * @iter: a #ClutterActorIter
16741  * @child: (out): return location for a #ClutterActor
16742  *
16743  * Advances the @iter and retrieves the previous child of the root
16744  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16745  *
16746  * If the iterator can advance, this function returns %TRUE and sets the
16747  * @child argument.
16748  *
16749  * If the iterator cannot advance, this function returns %FALSE, and
16750  * the contents of @child are undefined.
16751  *
16752  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16753  *
16754  * Since: 1.10
16755  */
16756 gboolean
16757 clutter_actor_iter_prev (ClutterActorIter  *iter,
16758                          ClutterActor     **child)
16759 {
16760   RealActorIter *ri = (RealActorIter *) iter;
16761
16762   g_return_val_if_fail (iter != NULL, FALSE);
16763   g_return_val_if_fail (ri->root != NULL, FALSE);
16764 #ifndef G_DISABLE_ASSERT
16765   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16766 #endif
16767
16768   if (ri->current == NULL)
16769     ri->current = ri->root->priv->last_child;
16770   else
16771     ri->current = ri->current->priv->prev_sibling;
16772
16773   if (child != NULL)
16774     *child = ri->current;
16775
16776   return ri->current != NULL;
16777 }
16778
16779 /**
16780  * clutter_actor_iter_remove:
16781  * @iter: a #ClutterActorIter
16782  *
16783  * Safely removes the #ClutterActor currently pointer to by the iterator
16784  * from its parent.
16785  *
16786  * This function can only be called after clutter_actor_iter_next() or
16787  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16788  * than once for the same actor.
16789  *
16790  * This function will call clutter_actor_remove_child() internally.
16791  *
16792  * Since: 1.10
16793  */
16794 void
16795 clutter_actor_iter_remove (ClutterActorIter *iter)
16796 {
16797   RealActorIter *ri = (RealActorIter *) iter;
16798   ClutterActor *cur;
16799
16800   g_return_if_fail (iter != NULL);
16801   g_return_if_fail (ri->root != NULL);
16802 #ifndef G_DISABLE_ASSERT
16803   g_return_if_fail (ri->age == ri->root->priv->age);
16804 #endif
16805   g_return_if_fail (ri->current != NULL);
16806
16807   cur = ri->current;
16808
16809   if (cur != NULL)
16810     {
16811       ri->current = cur->priv->prev_sibling;
16812
16813       clutter_actor_remove_child_internal (ri->root, cur,
16814                                            REMOVE_CHILD_DEFAULT_FLAGS);
16815
16816       ri->age += 1;
16817     }
16818 }
16819
16820 /**
16821  * clutter_actor_iter_destroy:
16822  * @iter: a #ClutterActorIter
16823  *
16824  * Safely destroys the #ClutterActor currently pointer to by the iterator
16825  * from its parent.
16826  *
16827  * This function can only be called after clutter_actor_iter_next() or
16828  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16829  * than once for the same actor.
16830  *
16831  * This function will call clutter_actor_destroy() internally.
16832  *
16833  * Since: 1.10
16834  */
16835 void
16836 clutter_actor_iter_destroy (ClutterActorIter *iter)
16837 {
16838   RealActorIter *ri = (RealActorIter *) iter;
16839   ClutterActor *cur;
16840
16841   g_return_if_fail (iter != NULL);
16842   g_return_if_fail (ri->root != NULL);
16843 #ifndef G_DISABLE_ASSERT
16844   g_return_if_fail (ri->age == ri->root->priv->age);
16845 #endif
16846   g_return_if_fail (ri->current != NULL);
16847
16848   cur = ri->current;
16849
16850   if (cur != NULL)
16851     {
16852       ri->current = cur->priv->prev_sibling;
16853
16854       clutter_actor_destroy (cur);
16855
16856       ri->age += 1;
16857     }
16858 }
16859
16860 static const ClutterAnimationInfo default_animation_info = {
16861   NULL,         /* transitions */
16862   NULL,         /* states */
16863   NULL,         /* cur_state */
16864 };
16865
16866 static void
16867 clutter_animation_info_free (gpointer data)
16868 {
16869   if (data != NULL)
16870     {
16871       ClutterAnimationInfo *info = data;
16872
16873       if (info->transitions != NULL)
16874         g_hash_table_unref (info->transitions);
16875
16876       if (info->states != NULL)
16877         g_array_unref (info->states);
16878
16879       g_slice_free (ClutterAnimationInfo, info);
16880     }
16881 }
16882
16883 const ClutterAnimationInfo *
16884 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16885 {
16886   const ClutterAnimationInfo *res;
16887   GObject *obj = G_OBJECT (self);
16888
16889   res = g_object_get_qdata (obj, quark_actor_animation_info);
16890   if (res != NULL)
16891     return res;
16892
16893   return &default_animation_info;
16894 }
16895
16896 ClutterAnimationInfo *
16897 _clutter_actor_get_animation_info (ClutterActor *self)
16898 {
16899   GObject *obj = G_OBJECT (self);
16900   ClutterAnimationInfo *res;
16901
16902   res = g_object_get_qdata (obj, quark_actor_animation_info);
16903   if (res == NULL)
16904     {
16905       res = g_slice_new (ClutterAnimationInfo);
16906
16907       *res = default_animation_info;
16908
16909       g_object_set_qdata_full (obj, quark_actor_animation_info,
16910                                res,
16911                                clutter_animation_info_free);
16912     }
16913
16914   return res;
16915 }
16916
16917 ClutterTransition *
16918 _clutter_actor_get_transition (ClutterActor *actor,
16919                                GParamSpec   *pspec)
16920 {
16921   const ClutterAnimationInfo *info;
16922
16923   info = _clutter_actor_get_animation_info_or_defaults (actor);
16924
16925   if (info->transitions == NULL)
16926     return NULL;
16927
16928   return g_hash_table_lookup (info->transitions, pspec->name);
16929 }
16930
16931 typedef struct _TransitionClosure
16932 {
16933   ClutterActor *actor;
16934   ClutterTransition *transition;
16935   gchar *name;
16936   gulong completed_id;
16937 } TransitionClosure;
16938
16939 static void
16940 transition_closure_free (gpointer data)
16941 {
16942   if (G_LIKELY (data != NULL))
16943     {
16944       TransitionClosure *clos = data;
16945
16946       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16947       g_free (clos->name);
16948
16949       g_slice_free (TransitionClosure, clos);
16950     }
16951 }
16952
16953 static void
16954 on_transition_completed (ClutterTransition *transition,
16955                          TransitionClosure *clos)
16956 {
16957   ClutterAnimationInfo *info;
16958
16959   info = _clutter_actor_get_animation_info (clos->actor);
16960
16961   /* this will take care of cleaning clos for us */
16962   g_hash_table_remove (info->transitions, clos->name);
16963 }
16964
16965 void
16966 _clutter_actor_update_transition (ClutterActor *actor,
16967                                   GParamSpec   *pspec,
16968                                   ...)
16969 {
16970   TransitionClosure *clos;
16971   ClutterInterval *interval;
16972   const ClutterAnimationInfo *info;
16973   va_list var_args;
16974   GType ptype;
16975   GValue initial = G_VALUE_INIT;
16976   GValue final = G_VALUE_INIT;
16977   char *error = NULL;
16978
16979   info = _clutter_actor_get_animation_info_or_defaults (actor);
16980
16981   if (info->transitions == NULL)
16982     return;
16983
16984   clos = g_hash_table_lookup (info->transitions, pspec->name);
16985   if (clos == NULL)
16986     return;
16987
16988   va_start (var_args, pspec);
16989
16990   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16991
16992   g_value_init (&initial, ptype);
16993   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16994                                         pspec->name,
16995                                         &initial);
16996
16997   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16998   if (error != NULL)
16999     {
17000       g_critical ("%s: %s", G_STRLOC, error);
17001       g_free (error);
17002       goto out;
17003     }
17004
17005   interval = clutter_transition_get_interval (clos->transition);
17006   clutter_interval_set_initial_value (interval, &initial);
17007   clutter_interval_set_final_value (interval, &final);
17008
17009   clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17010
17011 out:
17012   g_value_unset (&initial);
17013   g_value_unset (&final);
17014
17015   va_end (var_args);
17016 }
17017
17018 /*< private >*
17019  * _clutter_actor_create_transition:
17020  * @actor: a #ClutterActor
17021  * @pspec: the property used for the transition
17022  * @...: initial and final state
17023  *
17024  * Creates a #ClutterTransition for the property represented by @pspec.
17025  *
17026  * Return value: a #ClutterTransition
17027  */
17028 ClutterTransition *
17029 _clutter_actor_create_transition (ClutterActor *actor,
17030                                   GParamSpec   *pspec,
17031                                   ...)
17032 {
17033   ClutterAnimationInfo *info;
17034   ClutterTransition *res = NULL;
17035   gboolean call_restore = FALSE;
17036   TransitionClosure *clos;
17037   va_list var_args;
17038
17039   info = _clutter_actor_get_animation_info (actor);
17040
17041   if (info->states == NULL)
17042     {
17043       clutter_actor_save_easing_state (actor);
17044       call_restore = TRUE;
17045     }
17046
17047   if (info->transitions == NULL)
17048     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17049                                                NULL,
17050                                                transition_closure_free);
17051
17052   va_start (var_args, pspec);
17053
17054   clos = g_hash_table_lookup (info->transitions, pspec->name);
17055   if (clos == NULL)
17056     {
17057       ClutterInterval *interval;
17058       GValue initial = G_VALUE_INIT;
17059       GValue final = G_VALUE_INIT;
17060       GType ptype;
17061       char *error;
17062
17063       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17064
17065       G_VALUE_COLLECT_INIT (&initial, ptype,
17066                             var_args, 0,
17067                             &error);
17068       if (error != NULL)
17069         {
17070           g_critical ("%s: %s", G_STRLOC, error);
17071           g_free (error);
17072           goto out;
17073         }
17074
17075       G_VALUE_COLLECT_INIT (&final, ptype,
17076                             var_args, 0,
17077                             &error);
17078
17079       if (error != NULL)
17080         {
17081           g_critical ("%s: %s", G_STRLOC, error);
17082           g_value_unset (&initial);
17083           g_free (error);
17084           goto out;
17085         }
17086
17087       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17088
17089       g_value_unset (&initial);
17090       g_value_unset (&final);
17091
17092       res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17093                                              pspec->name);
17094
17095       clutter_transition_set_interval (res, interval);
17096       clutter_transition_set_remove_on_complete (res, TRUE);
17097
17098       clutter_actor_add_transition (actor, pspec->name, res);
17099     }
17100   else
17101     res = clos->transition;
17102
17103 out:
17104   if (call_restore)
17105     clutter_actor_restore_easing_state (actor);
17106
17107   va_end (var_args);
17108
17109   return res;
17110 }
17111
17112 /**
17113  * clutter_actor_add_transition:
17114  * @self: a #ClutterActor
17115  * @name: the name of the transition to add
17116  * @transition: the #ClutterTransition to add
17117  *
17118  * Adds a @transition to the #ClutterActor's list of animations.
17119  *
17120  * The @name string is a per-actor unique identifier of the @transition: only
17121  * one #ClutterTransition can be associated to the specified @name.
17122  *
17123  * The @transition will be given the easing duration, mode, and delay
17124  * associated to the actor's current easing state; it is possible to modify
17125  * these values after calling clutter_actor_add_transition().
17126  *
17127  * This function is usually called implicitly when modifying an animatable
17128  * property.
17129  *
17130  * Since: 1.10
17131  */
17132 void
17133 clutter_actor_add_transition (ClutterActor      *self,
17134                               const char        *name,
17135                               ClutterTransition *transition)
17136 {
17137   ClutterTimeline *timeline;
17138   TransitionClosure *clos;
17139   ClutterAnimationInfo *info;
17140
17141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17142   g_return_if_fail (name != NULL);
17143   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17144
17145   info = _clutter_actor_get_animation_info (self);
17146
17147   if (info->cur_state == NULL)
17148     {
17149       g_warning ("No easing state is defined for the actor '%s'; you "
17150                  "must call clutter_actor_save_easing_state() before "
17151                  "calling clutter_actor_add_transition().",
17152                  _clutter_actor_get_debug_name (self));
17153       return;
17154     }
17155
17156   if (info->transitions == NULL)
17157     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17158                                                NULL,
17159                                                transition_closure_free);
17160
17161   if (g_hash_table_lookup (info->transitions, name) != NULL)
17162     {
17163       g_warning ("A transition with name '%s' already exists for "
17164                  "the actor '%s'",
17165                  name,
17166                  _clutter_actor_get_debug_name (self));
17167       return;
17168     }
17169
17170   timeline = CLUTTER_TIMELINE (transition);
17171
17172   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17173   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17174   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17175
17176   clos = g_slice_new (TransitionClosure);
17177   clos->actor = self;
17178   clos->transition = transition;
17179   clos->name = g_strdup (name);
17180   clos->completed_id = g_signal_connect (timeline, "completed",
17181                                          G_CALLBACK (on_transition_completed),
17182                                          clos);
17183
17184   g_hash_table_insert (info->transitions, clos->name, clos);
17185 }
17186
17187 /**
17188  * clutter_actor_remove_transition:
17189  * @self: a #ClutterActor
17190  * @name: the name of the transition to remove
17191  *
17192  * Removes the transition stored inside a #ClutterActor using @name
17193  * identifier.
17194  *
17195  * Since: 1.10
17196  */
17197 void
17198 clutter_actor_remove_transition (ClutterActor *self,
17199                                  const char   *name)
17200 {
17201   const ClutterAnimationInfo *info;
17202
17203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17204   g_return_if_fail (name != NULL);
17205
17206   info = _clutter_actor_get_animation_info_or_defaults (self);
17207
17208   if (info->transitions == NULL)
17209     return;
17210
17211   g_hash_table_remove (info->transitions, name);
17212 }
17213
17214 /**
17215  * clutter_actor_remove_all_transitions:
17216  * @self: a #ClutterActor
17217  *
17218  * Removes all transitions associated to @self.
17219  *
17220  * Since: 1.10
17221  */
17222 void
17223 clutter_actor_remove_all_transitions (ClutterActor *self)
17224 {
17225   const ClutterAnimationInfo *info;
17226
17227   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17228
17229   info = _clutter_actor_get_animation_info_or_defaults (self);
17230   if (info->transitions == NULL)
17231     return;
17232
17233   g_hash_table_remove_all (info->transitions);
17234 }
17235
17236 /**
17237  * clutter_actor_set_easing_duration:
17238  * @self: a #ClutterActor
17239  * @msecs: the duration of the easing, or %NULL
17240  *
17241  * Sets the duration of the tweening for animatable properties
17242  * of @self for the current easing state.
17243  *
17244  * Since: 1.10
17245  */
17246 void
17247 clutter_actor_set_easing_duration (ClutterActor *self,
17248                                    guint         msecs)
17249 {
17250   ClutterAnimationInfo *info;
17251
17252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17253
17254   info = _clutter_actor_get_animation_info (self);
17255
17256   if (info->cur_state == NULL)
17257     {
17258       g_warning ("You must call clutter_actor_save_easing_state() prior "
17259                  "to calling clutter_actor_set_easing_duration().");
17260       return;
17261     }
17262
17263   if (info->cur_state->easing_duration != msecs)
17264     info->cur_state->easing_duration = msecs;
17265 }
17266
17267 /**
17268  * clutter_actor_get_easing_duration:
17269  * @self: a #ClutterActor
17270  *
17271  * Retrieves the duration of the tweening for animatable
17272  * properties of @self for the current easing state.
17273  *
17274  * Return value: the duration of the tweening, in milliseconds
17275  *
17276  * Since: 1.10
17277  */
17278 guint
17279 clutter_actor_get_easing_duration (ClutterActor *self)
17280 {
17281   const ClutterAnimationInfo *info;
17282
17283   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17284
17285   info = _clutter_actor_get_animation_info_or_defaults (self);
17286
17287   if (info->cur_state != NULL)
17288     return info->cur_state->easing_duration;
17289
17290   return 0;
17291 }
17292
17293 /**
17294  * clutter_actor_set_easing_mode:
17295  * @self: a #ClutterActor
17296  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17297  *
17298  * Sets the easing mode for the tweening of animatable properties
17299  * of @self.
17300  *
17301  * Since: 1.10
17302  */
17303 void
17304 clutter_actor_set_easing_mode (ClutterActor         *self,
17305                                ClutterAnimationMode  mode)
17306 {
17307   ClutterAnimationInfo *info;
17308
17309   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17310   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17311   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17312
17313   info = _clutter_actor_get_animation_info (self);
17314
17315   if (info->cur_state == NULL)
17316     {
17317       g_warning ("You must call clutter_actor_save_easing_state() prior "
17318                  "to calling clutter_actor_set_easing_mode().");
17319       return;
17320     }
17321
17322   if (info->cur_state->easing_mode != mode)
17323     info->cur_state->easing_mode = mode;
17324 }
17325
17326 /**
17327  * clutter_actor_get_easing_mode:
17328  * @self: a #ClutterActor
17329  *
17330  * Retrieves the easing mode for the tweening of animatable properties
17331  * of @self for the current easing state.
17332  *
17333  * Return value: an easing mode
17334  *
17335  * Since: 1.10
17336  */
17337 ClutterAnimationMode
17338 clutter_actor_get_easing_mode (ClutterActor *self)
17339 {
17340   const ClutterAnimationInfo *info;
17341
17342   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17343
17344   info = _clutter_actor_get_animation_info_or_defaults (self);
17345
17346   if (info->cur_state != NULL)
17347     return info->cur_state->easing_mode;
17348
17349   return CLUTTER_EASE_OUT_CUBIC;
17350 }
17351
17352 /**
17353  * clutter_actor_set_easing_delay:
17354  * @self: a #ClutterActor
17355  * @msecs: the delay before the start of the tweening, in milliseconds
17356  *
17357  * Sets the delay that should be applied before tweening animatable
17358  * properties.
17359  *
17360  * Since: 1.10
17361  */
17362 void
17363 clutter_actor_set_easing_delay (ClutterActor *self,
17364                                 guint         msecs)
17365 {
17366   ClutterAnimationInfo *info;
17367
17368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17369
17370   info = _clutter_actor_get_animation_info (self);
17371
17372   if (info->cur_state == NULL)
17373     {
17374       g_warning ("You must call clutter_actor_save_easing_state() prior "
17375                  "to calling clutter_actor_set_easing_delay().");
17376       return;
17377     }
17378
17379   if (info->cur_state->easing_delay != msecs)
17380     info->cur_state->easing_delay = msecs;
17381 }
17382
17383 /**
17384  * clutter_actor_get_easing_delay:
17385  * @self: a #ClutterActor
17386  *
17387  * Retrieves the delay that should be applied when tweening animatable
17388  * properties.
17389  *
17390  * Return value: a delay, in milliseconds
17391  *
17392  * Since: 1.10
17393  */
17394 guint
17395 clutter_actor_get_easing_delay (ClutterActor *self)
17396 {
17397   const ClutterAnimationInfo *info;
17398
17399   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17400
17401   info = _clutter_actor_get_animation_info_or_defaults (self);
17402
17403   if (info->cur_state != NULL)
17404     return info->cur_state->easing_delay;
17405
17406   return 0;
17407 }
17408
17409 /**
17410  * clutter_actor_get_transition:
17411  * @self: a #ClutterActor
17412  * @name: the name of the transition
17413  *
17414  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17415  * transition @name.
17416  *
17417  * Transitions created for animatable properties use the name of the
17418  * property itself, for instance the code below:
17419  *
17420  * |[
17421  *   clutter_actor_set_easing_duration (actor, 1000);
17422  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17423  *
17424  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17425  *   g_signal_connect (transition, "completed",
17426  *                     G_CALLBACK (on_transition_complete),
17427  *                     actor);
17428  * ]|
17429  *
17430  * will call the <function>on_transition_complete</function> callback when
17431  * the transition is complete.
17432  *
17433  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17434  *   was found to match the passed name; the returned instance is owned
17435  *   by Clutter and it should not be freed
17436  *
17437  * Since: 1.10
17438  */
17439 ClutterTransition *
17440 clutter_actor_get_transition (ClutterActor *self,
17441                               const char   *name)
17442 {
17443   TransitionClosure *clos;
17444   const ClutterAnimationInfo *info;
17445
17446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17447   g_return_val_if_fail (name != NULL, NULL);
17448
17449   info = _clutter_actor_get_animation_info_or_defaults (self);
17450
17451   if (info->transitions == NULL)
17452     return NULL;
17453
17454   clos = g_hash_table_lookup (info->transitions, name);
17455   if (clos == NULL)
17456     return NULL;
17457
17458   return clos->transition;
17459 }
17460
17461 /**
17462  * clutter_actor_save_easing_state:
17463  * @self: a #ClutterActor
17464  *
17465  * Saves the current easing state for animatable properties, and creates
17466  * a new state with the default values for easing mode and duration.
17467  *
17468  * Since: 1.10
17469  */
17470 void
17471 clutter_actor_save_easing_state (ClutterActor *self)
17472 {
17473   ClutterAnimationInfo *info;
17474   AState new_state;
17475
17476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17477
17478   info = _clutter_actor_get_animation_info (self);
17479
17480   if (info->states == NULL)
17481     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17482
17483   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17484   new_state.easing_duration = 250;
17485   new_state.easing_delay = 0;
17486
17487   g_array_append_val (info->states, new_state);
17488
17489   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17490 }
17491
17492 /**
17493  * clutter_actor_restore_easing_state:
17494  * @self: a #ClutterActor
17495  *
17496  * Restores the easing state as it was prior to a call to
17497  * clutter_actor_save_easing_state().
17498  *
17499  * Since: 1.10
17500  */
17501 void
17502 clutter_actor_restore_easing_state (ClutterActor *self)
17503 {
17504   ClutterAnimationInfo *info;
17505
17506   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17507
17508   info = _clutter_actor_get_animation_info (self);
17509
17510   if (info->states == NULL)
17511     {
17512       g_critical ("The function clutter_actor_restore_easing_state() has "
17513                   "called without a previous call to "
17514                   "clutter_actor_save_easing_state().");
17515       return;
17516     }
17517
17518   g_array_remove_index (info->states, info->states->len - 1);
17519
17520   if (info->states->len > 0)
17521     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17522   else
17523     {
17524       g_array_unref (info->states);
17525       info->states = NULL;
17526     }
17527 }
17528
17529 /**
17530  * clutter_actor_set_content:
17531  * @self: a #ClutterActor
17532  * @content: (allow-none): a #ClutterContent, or %NULL
17533  *
17534  * Sets the contents of a #ClutterActor.
17535  *
17536  * Since: 1.10
17537  */
17538 void
17539 clutter_actor_set_content (ClutterActor   *self,
17540                            ClutterContent *content)
17541 {
17542   ClutterActorPrivate *priv;
17543
17544   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17545   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17546
17547   priv = self->priv;
17548
17549   if (priv->content != NULL)
17550     {
17551       _clutter_content_detached (priv->content, self);
17552       g_object_unref (priv->content);
17553     }
17554
17555   priv->content = content;
17556
17557   if (priv->content != NULL)
17558     {
17559       g_object_ref (priv->content);
17560       _clutter_content_attached (priv->content, self);
17561     }
17562
17563   /* given that the content is always painted within the allocation,
17564    * we only need to queue a redraw here
17565    */
17566   clutter_actor_queue_redraw (self);
17567
17568   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17569
17570   /* if the content gravity is not resize-fill, and the new content has a
17571    * different preferred size than the previous one, then the content box
17572    * may have been changed. since we compute that lazily, we just notify
17573    * here, and let whomever watches :content-box do whatever they need to
17574    * do.
17575    */
17576   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17577     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17578 }
17579
17580 /**
17581  * clutter_actor_get_content:
17582  * @self: a #ClutterActor
17583  *
17584  * Retrieves the contents of @self.
17585  *
17586  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17587  *   or %NULL if none was set
17588  *
17589  * Since: 1.10
17590  */
17591 ClutterContent *
17592 clutter_actor_get_content (ClutterActor *self)
17593 {
17594   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17595
17596   return self->priv->content;
17597 }
17598
17599 /**
17600  * clutter_actor_set_content_gravity:
17601  * @self: a #ClutterActor
17602  * @gravity: the #ClutterContentGravity
17603  *
17604  * Sets the gravity of the #ClutterContent used by @self.
17605  *
17606  * See the description of the #ClutterActor:content-gravity property for
17607  * more information.
17608  *
17609  * Since: 1.10
17610  */
17611 void
17612 clutter_actor_set_content_gravity (ClutterActor *self,
17613                                    ClutterContentGravity  gravity)
17614 {
17615   ClutterActorPrivate *priv;
17616
17617   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17618
17619   priv = self->priv;
17620
17621   if (priv->content_gravity == gravity)
17622     return;
17623
17624   priv->content_gravity = gravity;
17625
17626   clutter_actor_queue_redraw (self);
17627
17628   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17629   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17630 }
17631
17632 /**
17633  * clutter_actor_get_content_gravity:
17634  * @self: a #ClutterActor
17635  *
17636  * Retrieves the content gravity as set using
17637  * clutter_actor_get_content_gravity().
17638  *
17639  * Return value: the content gravity
17640  *
17641  * Since: 1.10
17642  */
17643 ClutterContentGravity
17644 clutter_actor_get_content_gravity (ClutterActor *self)
17645 {
17646   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17647                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17648
17649   return self->priv->content_gravity;
17650 }
17651
17652 /**
17653  * clutter_actor_get_content_box:
17654  * @self: a #ClutterActor
17655  * @box: (out caller-allocates): the return location for the bounding
17656  *   box for the #ClutterContent
17657  *
17658  * Retrieves the bounding box for the #ClutterContent of @self.
17659  *
17660  * The bounding box is relative to the actor's allocation.
17661  *
17662  * If no #ClutterContent is set for @self, or if @self has not been
17663  * allocated yet, then the result is undefined.
17664  *
17665  * The content box is guaranteed to be, at most, as big as the allocation
17666  * of the #ClutterActor.
17667  *
17668  * If the #ClutterContent used by the actor has a preferred size, then
17669  * it is possible to modify the content box by using the
17670  * #ClutterActor:content-gravity property.
17671  *
17672  * Since: 1.10
17673  */
17674 void
17675 clutter_actor_get_content_box (ClutterActor    *self,
17676                                ClutterActorBox *box)
17677 {
17678   ClutterActorPrivate *priv;
17679   gfloat content_w, content_h;
17680   gfloat alloc_w, alloc_h;
17681
17682   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17683   g_return_if_fail (box != NULL);
17684
17685   priv = self->priv;
17686
17687   box->x1 = 0.f;
17688   box->y1 = 0.f;
17689   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17690   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17691
17692   if (priv->content == NULL)
17693     return;
17694
17695   /* no need to do any more work */
17696   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17697     return;
17698
17699   /* if the content does not have a preferred size then there is
17700    * no point in computing the content box
17701    */
17702   if (!clutter_content_get_preferred_size (priv->content,
17703                                            &content_w,
17704                                            &content_h))
17705     return;
17706
17707   alloc_w = box->x2;
17708   alloc_h = box->y2;
17709
17710   switch (priv->content_gravity)
17711     {
17712     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17713       box->x2 = box->x1 + MIN (content_w, alloc_w);
17714       box->y2 = box->y1 + MIN (content_h, alloc_h);
17715       break;
17716
17717     case CLUTTER_CONTENT_GRAVITY_TOP:
17718       if (alloc_w > content_w)
17719         {
17720           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17721           box->x2 = box->x1 + content_w;
17722         }
17723       box->y2 = box->y1 + MIN (content_h, alloc_h);
17724       break;
17725
17726     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17727       if (alloc_w > content_w)
17728         {
17729           box->x1 += (alloc_w - content_w);
17730           box->x2 = box->x1 + content_w;
17731         }
17732       box->y2 = box->y1 + MIN (content_h, alloc_h);
17733       break;
17734
17735     case CLUTTER_CONTENT_GRAVITY_LEFT:
17736       box->x2 = box->x1 + MIN (content_w, alloc_w);
17737       if (alloc_h > content_h)
17738         {
17739           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17740           box->y2 = box->y1 + content_h;
17741         }
17742       break;
17743
17744     case CLUTTER_CONTENT_GRAVITY_CENTER:
17745       if (alloc_w > content_w)
17746         {
17747           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17748           box->x2 = box->x1 + content_w;
17749         }
17750       if (alloc_h > content_h)
17751         {
17752           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17753           box->y2 = box->y1 + content_h;
17754         }
17755       break;
17756
17757     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17758       if (alloc_w > content_w)
17759         {
17760           box->x1 += (alloc_w - content_w);
17761           box->x2 = box->x1 + content_w;
17762         }
17763       if (alloc_h > content_h)
17764         {
17765           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17766           box->y2 = box->y1 + content_h;
17767         }
17768       break;
17769
17770     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17771       box->x2 = box->x1 + MIN (content_w, alloc_w);
17772       if (alloc_h > content_h)
17773         {
17774           box->y1 += (alloc_h - content_h);
17775           box->y2 = box->y1 + content_h;
17776         }
17777       break;
17778
17779     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17780       if (alloc_w > content_w)
17781         {
17782           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17783           box->x2 = box->x1 + content_w;
17784         }
17785       if (alloc_h > content_h)
17786         {
17787           box->y1 += (alloc_h - content_h);
17788           box->y2 = box->y1 + content_h;
17789         }
17790       break;
17791
17792     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17793       if (alloc_w > content_w)
17794         {
17795           box->x1 += (alloc_w - content_w);
17796           box->x2 = box->x1 + content_w;
17797         }
17798       if (alloc_h > content_h)
17799         {
17800           box->y1 += (alloc_h - content_h);
17801           box->y2 = box->y1 + content_h;
17802         }
17803       break;
17804
17805     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17806       g_assert_not_reached ();
17807       break;
17808
17809     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17810       {
17811         double r_c = content_w / content_h;
17812         double r_a = alloc_w / alloc_h;
17813
17814         if (r_c >= 1.0)
17815           {
17816             if (r_a >= 1.0)
17817               {
17818                 box->x1 = 0.f;
17819                 box->x2 = alloc_w;
17820
17821                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17822                 box->y2 = box->y1 + (alloc_w * r_c);
17823               }
17824             else
17825               {
17826                 box->y1 = 0.f;
17827                 box->y2 = alloc_h;
17828
17829                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17830                 box->x2 = box->x1 + (alloc_h * r_c);
17831               }
17832           }
17833         else
17834           {
17835             if (r_a >= 1.0)
17836               {
17837                 box->y1 = 0.f;
17838                 box->y2 = alloc_h;
17839
17840                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17841                 box->x2 = box->x1 + (alloc_h * r_c);
17842               }
17843             else
17844               {
17845                 box->x1 = 0.f;
17846                 box->x2 = alloc_w;
17847
17848                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17849                 box->y2 = box->y1 + (alloc_w * r_c);
17850               }
17851           }
17852       }
17853       break;
17854     }
17855 }
17856
17857 /**
17858  * clutter_actor_set_content_scaling_filters:
17859  * @self: a #ClutterActor
17860  * @min_filter: the minification filter for the content
17861  * @mag_filter: the magnification filter for the content
17862  *
17863  * Sets the minification and magnification filter to be applied when
17864  * scaling the #ClutterActor:content of a #ClutterActor.
17865  *
17866  * The #ClutterActor:minification-filter will be used when reducing
17867  * the size of the content; the #ClutterActor:magnification-filter
17868  * will be used when increasing the size of the content.
17869  *
17870  * Since: 1.10
17871  */
17872 void
17873 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
17874                                            ClutterScalingFilter  min_filter,
17875                                            ClutterScalingFilter  mag_filter)
17876 {
17877   ClutterActorPrivate *priv;
17878   gboolean changed;
17879   GObject *obj;
17880
17881   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17882
17883   priv = self->priv;
17884   obj = G_OBJECT (self);
17885
17886   g_object_freeze_notify (obj);
17887
17888   changed = FALSE;
17889
17890   if (priv->min_filter != min_filter)
17891     {
17892       priv->min_filter = min_filter;
17893       changed = TRUE;
17894
17895       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17896     }
17897
17898   if (priv->mag_filter != mag_filter)
17899     {
17900       priv->mag_filter = mag_filter;
17901       changed = TRUE;
17902
17903       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17904     }
17905
17906   if (changed)
17907     clutter_actor_queue_redraw (self);
17908
17909   g_object_thaw_notify (obj);
17910 }
17911
17912 /**
17913  * clutter_actor_get_content_scaling_filters:
17914  * @self: a #ClutterActor
17915  * @min_filter: (out) (allow-none): return location for the minification
17916  *   filter, or %NULL
17917  * @mag_filter: (out) (allow-none): return location for the magnification
17918  *   filter, or %NULL
17919  *
17920  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17921  *
17922  * Since: 1.10
17923  */
17924 void
17925 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
17926                                            ClutterScalingFilter *min_filter,
17927                                            ClutterScalingFilter *mag_filter)
17928 {
17929   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17930
17931   if (min_filter != NULL)
17932     *min_filter = self->priv->min_filter;
17933
17934   if (mag_filter != NULL)
17935     *mag_filter = self->priv->mag_filter;
17936 }