231e4e92f2d1bdcf2009be8e614fa0d260f97910
[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-angle-x and #ClutterActor:rotation-center-x;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-angle-y and #ClutterActor:rotation-center-y;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-angle-z and #ClutterActor:rotation-center-z;</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="../../../../examples/basic-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-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297  * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
298  *
299  * clutter_actor_add_transition (actor, "animate-opacity", transition);
300  *     </programlisting></informalexample>
301  *     <para>The example above will animate the #ClutterActor:opacity property
302  *     of an actor between fully opaque and fully transparent, and back, over
303  *     a span of 3 seconds. The animation does not begin until it is added to
304  *     the actor.</para>
305  *     <para>The explicit animation API should also be used when using custom
306  *     animatable properties for #ClutterAction, #ClutterConstraint, and
307  *     #ClutterEffect instances associated to an actor; see the section on
308  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
309  *     animatable properties below</ulink> for an example.</para>
310  *     <para>Finally, explicit animations are useful for creating animations
311  *     that run continuously, for instance:</para>
312  *     <informalexample><programlisting>
313  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
314  * ClutterTransition *transition;
315  * ClutterInterval *interval;
316  *
317  * transition = clutter_property_transition_new ("opacity");
318  *
319  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
320  * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321  * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
322  *
323  * /&ast; over a one second duration, running an infinite amount of times &ast;/
324  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326  *
327  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
328  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329  *
330  * /&ast; and we want to use an easing function that eases both in and out &ast;/
331  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
333  *
334  * /&ast; add the transition to the desired actor; this will
335  *  &ast; start the animation.
336  *  &ast;/
337  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338  *     </programlisting></informalexample>
339  *   </formalpara>
340  * </refsect2>
341  *
342  * <refsect2 id="ClutterActor-subclassing">
343  *   <title>Implementing an actor</title>
344  *   <para>Careful consideration should be given when deciding to implement
345  *   a #ClutterActor sub-class. It is generally recommended to implement a
346  *   sub-class of #ClutterActor only for actors that should be used as leaf
347  *   nodes of a scene graph.</para>
348  *   <para>If your actor should be painted in a custom way, you should
349  *   override the #ClutterActor::paint signal class handler. You can either
350  *   opt to chain up to the parent class implementation or decide to fully
351  *   override the default paint implementation; Clutter will set up the
352  *   transformations and clip regions prior to emitting the #ClutterActor::paint
353  *   signal.</para>
354  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
355  *   #ClutterActorClass.get_preferred_height() virtual functions it is
356  *   possible to change or provide the preferred size of an actor; similarly,
357  *   by overriding the #ClutterActorClass.allocate() virtual function it is
358  *   possible to control the layout of the children of an actor. Make sure to
359  *   always chain up to the parent implementation of the
360  *   #ClutterActorClass.allocate() virtual function.</para>
361  *   <para>In general, it is strongly encouraged to use delegation and
362  *   composition instead of direct subclassing.</para>
363  * </refsect2>
364  *
365  * <refsect2 id="ClutterActor-script">
366  *   <title>ClutterActor custom properties for #ClutterScript</title>
367  *   <para>#ClutterActor defines a custom "rotation" property which
368  *   allows a short-hand description of the rotations to be applied
369  *   to an actor.</para>
370  *   <para>The syntax of the "rotation" property is the following:</para>
371  *   <informalexample>
372  *     <programlisting>
373  * "rotation" : [
374  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
375  * ]
376  *     </programlisting>
377  *   </informalexample>
378  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380  *   floating point value representing the rotation angle on the given axis,
381  *   in degrees.</para>
382  *   <para>The <emphasis>center</emphasis> array is optional, and if present
383  *   it must contain the center of rotation as described by two coordinates:
384  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385  *   "z-axis".</para>
386  *   <para>#ClutterActor also defines a scriptable "margin" property which
387  *   follows the CSS "margin" shorthand.
388  *   <informalexample>
389  *     <programlisting>
390  * // 4 values
391  * "margin" : [ &lt;top&gt;, &lt;right&gt;, &lt;bottom&gt; &lt;left&gt; ]
392  * // 3 values
393  * "margin" : [ &lt;top&gt;, &lt;left/right&gt;, &lt;bottom&gt; ]
394  * // 2 values
395  * "margin" : [ &lt;top/bottom&gt;, &lt;left/right&gt; ]
396  * // 1 value
397  * "margin" : [ &lt;top/right/bottom/left&gt; ]
398  *     </programlisting>
399  *   </informalexample>
400  *   </para>
401  *   <para>#ClutterActor will also parse every positional and dimensional
402  *   property defined as a string through clutter_units_from_string(); you
403  *   should read the documentation for the #ClutterUnits parser format for
404  *   the valid units and syntax.</para>
405  * </refsect2>
406  *
407  * <refsect2 id="ClutterActor-custom-animatable-properties">
408  *   <title>Custom animatable properties</title>
409  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
410  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
411  *   instance for animation purposes.</para>
412  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413  *   property it is necessary to set the #ClutterActorMeta:name property on the
414  *   given action or constraint.</para>
415  *   <para>The property can be accessed using the following syntax:</para>
416  *   <informalexample>
417  *     <programlisting>
418  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
419  *     </programlisting>
420  *   </informalexample>
421  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422  *   <para>The <emphasis>section</emphasis> fragment can be one between
423  *   "actions", "constraints" and "effects".</para>
424  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425  *   action or constraint, as specified by the #ClutterActorMeta:name
426  *   property.</para>
427  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
428  *   action or constraint property to be animated.</para>
429  *   <para>The example below animates a #ClutterBindConstraint applied to an
430  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
432  *   its initial state is overlapping the actor to which is bound to.</para>
433  *   <informalexample><programlisting>
434  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436  * clutter_actor_add_constraint (rect, constraint);
437  *
438  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440  * clutter_actor_add_constraint (rect, constraint);
441  *
442  * clutter_actor_set_reactive (origin, TRUE);
443  *
444  * g_signal_connect (origin, "button-press-event",
445  *                   G_CALLBACK (on_button_press),
446  *                   rect);
447  *   </programlisting></informalexample>
448  *   <para>On button press, the rectangle "slides" from behind the actor to
449  *   which is bound to, using the #ClutterBindConstraint:offset property to
450  *   achieve the effect:</para>
451  *   <informalexample><programlisting>
452  * gboolean
453  * on_button_press (ClutterActor *origin,
454  *                  ClutterEvent *event,
455  *                  ClutterActor *rect)
456  * {
457  *   ClutterTransition *transition;
458  *   ClutterInterval *interval;
459  *
460  *   /&ast; the offset that we want to apply; this will make the actor
461  *    &ast; slide in from behind the origin and rest at the right of
462  *    &ast; the origin, plus a padding value.
463  *    &ast;/
464  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
465  *
466  *   /&ast; the property we wish to animate; the "@constraints" section
467  *    &ast; tells Clutter to check inside the constraints associated
468  *    &ast; with the actor; the "bind-x" section is the name of the
469  *    &ast; constraint; and the "offset" is the name of the property
470  *    &ast; on the constraint.
471  *    &ast;/
472  *   const char *prop = "@constraints.bind-x.offset";
473  *
474  *   /&ast; create a new transition for the given property &ast;/
475  *   transition = clutter_property_transition_new (prop);
476  *
477  *   /&ast; set the easing mode and duration &ast;/
478  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479  *                                       CLUTTER_EASE_OUT_CUBIC);
480  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
481  *
482  *   /&ast; create the interval with the initial and final values &ast;/
483  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484  *   clutter_transition_set_interval (transition, interval);
485  *
486  *   /&ast; add the transition to the actor; this causes the animation
487  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
488  *    &ast; the transition later.
489  *    &ast;/
490  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
491  *
492  *   /&ast; we handled the event &ast;/
493  *   return CLUTTER_EVENT_STOP;
494  * }
495  *   </programlisting></informalexample>
496  * </refsect2>
497  */
498
499 /**
500  * CLUTTER_ACTOR_IS_MAPPED:
501  * @a: a #ClutterActor
502  *
503  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
504  *
505  * The mapped state is set when the actor is visible and all its parents up
506  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
507  *
508  * This check can be used to see if an actor is going to be painted, as only
509  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
510  *
511  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512  * not be checked directly; instead, the recommended usage is to connect a
513  * handler on the #GObject::notify signal for the #ClutterActor:mapped
514  * property of #ClutterActor, and check the presence of
515  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
516  *
517  * It is also important to note that Clutter may delay the changes of
518  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519  * limitations, or during the reparenting of an actor, to optimize
520  * unnecessary (and potentially expensive) state changes.
521  *
522  * Since: 0.2
523  */
524
525 /**
526  * CLUTTER_ACTOR_IS_REALIZED:
527  * @a: a #ClutterActor
528  *
529  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
530  *
531  * The realized state has an actor-dependant interpretation. If an
532  * actor wants to delay allocating resources until it is attached to a
533  * stage, it may use the realize state to do so. However it is
534  * perfectly acceptable for an actor to allocate Cogl resources before
535  * being realized because there is only one drawing context used by Clutter
536  * so any resources will work on any stage.  If an actor is mapped it
537  * must also be realized, but an actor can be realized and unmapped
538  * (this is so hiding an actor temporarily doesn't do an expensive
539  * unrealize/realize).
540  *
541  * To be realized an actor must be inside a stage, and all its parents
542  * must be realized.
543  *
544  * Since: 0.2
545  */
546
547 /**
548  * CLUTTER_ACTOR_IS_VISIBLE:
549  * @a: a #ClutterActor
550  *
551  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552  * Equivalent to the ClutterActor::visible object property.
553  *
554  * Note that an actor is only painted onscreen if it's mapped, which
555  * means it's visible, and all its parents are visible, and one of the
556  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
557  *
558  * Since: 0.2
559  */
560
561 /**
562  * CLUTTER_ACTOR_IS_REACTIVE:
563  * @a: a #ClutterActor
564  *
565  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
566  *
567  * Only reactive actors will receive event-related signals.
568  *
569  * Since: 0.6
570  */
571
572 #ifdef HAVE_CONFIG_H
573 #include "config.h"
574 #endif
575
576 #include <math.h>
577
578 #include <gobject/gvaluecollector.h>
579
580 #include <cogl/cogl.h>
581
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
584
585 #include "clutter-actor-private.h"
586
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-easing.h"
597 #include "clutter-effect-private.h"
598 #include "clutter-enum-types.h"
599 #include "clutter-fixed-layout.h"
600 #include "clutter-flatten-effect.h"
601 #include "clutter-interval.h"
602 #include "clutter-main.h"
603 #include "clutter-marshal.h"
604 #include "clutter-paint-nodes.h"
605 #include "clutter-paint-node-private.h"
606 #include "clutter-paint-volume-private.h"
607 #include "clutter-private.h"
608 #include "clutter-profile.h"
609 #include "clutter-property-transition.h"
610 #include "clutter-scriptable.h"
611 #include "clutter-script-private.h"
612 #include "clutter-stage-private.h"
613 #include "clutter-timeline.h"
614 #include "clutter-transition.h"
615 #include "clutter-units.h"
616
617 #include "deprecated/clutter-actor.h"
618 #include "deprecated/clutter-behaviour.h"
619 #include "deprecated/clutter-container.h"
620
621 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
622 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
623
624 /* Internal enum used to control mapped state update.  This is a hint
625  * which indicates when to do something other than just enforce
626  * invariants.
627  */
628 typedef enum {
629   MAP_STATE_CHECK,           /* just enforce invariants. */
630   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
631                               * used when about to unparent.
632                               */
633   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
634                               * used to set mapped on toplevels.
635                               */
636   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
637                               * used just before unmapping parent.
638                               */
639 } MapStateChange;
640
641 /* 3 entries should be a good compromise, few layout managers
642  * will ask for 3 different preferred size in each allocation cycle */
643 #define N_CACHED_SIZE_REQUESTS 3
644
645 struct _ClutterActorPrivate
646 {
647   /* request mode */
648   ClutterRequestMode request_mode;
649
650   /* our cached size requests for different width / height */
651   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
652   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
653
654   /* An age of 0 means the entry is not set */
655   guint cached_height_age;
656   guint cached_width_age;
657
658   /* the bounding box of the actor, relative to the parent's
659    * allocation
660    */
661   ClutterActorBox allocation;
662   ClutterAllocationFlags allocation_flags;
663
664   /* clip, in actor coordinates */
665   cairo_rectangle_t clip;
666
667   /* the cached transformation matrix; see apply_transform() */
668   CoglMatrix transform;
669
670   guint8 opacity;
671   gint opacity_override;
672
673   ClutterOffscreenRedirect offscreen_redirect;
674
675   /* This is an internal effect used to implement the
676      offscreen-redirect property */
677   ClutterEffect *flatten_effect;
678
679   /* scene graph */
680   ClutterActor *parent;
681   ClutterActor *prev_sibling;
682   ClutterActor *next_sibling;
683   ClutterActor *first_child;
684   ClutterActor *last_child;
685
686   gint n_children;
687
688   /* tracks whenever the children of an actor are changed; the
689    * age is incremented by 1 whenever an actor is added or
690    * removed. the age is not incremented when the first or the
691    * last child pointers are changed, or when grandchildren of
692    * an actor are changed.
693    */
694   gint age;
695
696   gchar *name; /* a non-unique name, used for debugging */
697   guint32 id; /* unique id, used for backward compatibility */
698
699   gint32 pick_id; /* per-stage unique id, used for picking */
700
701   /* a back-pointer to the Pango context that we can use
702    * to create pre-configured PangoLayout
703    */
704   PangoContext *pango_context;
705
706   /* the text direction configured for this child - either by
707    * application code, or by the actor's parent
708    */
709   ClutterTextDirection text_direction;
710
711   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
712   gint internal_child;
713
714   /* meta classes */
715   ClutterMetaGroup *actions;
716   ClutterMetaGroup *constraints;
717   ClutterMetaGroup *effects;
718
719   /* delegate object used to allocate the children of this actor */
720   ClutterLayoutManager *layout_manager;
721
722   /* delegate object used to paint the contents of this actor */
723   ClutterContent *content;
724
725   ClutterActorBox content_box;
726   ClutterContentGravity content_gravity;
727   ClutterScalingFilter min_filter;
728   ClutterScalingFilter mag_filter;
729   ClutterContentRepeat content_repeat;
730
731   /* used when painting, to update the paint volume */
732   ClutterEffect *current_effect;
733
734   /* This is used to store an effect which needs to be redrawn. A
735      redraw can be queued to start from a particular effect. This is
736      used by parametrised effects that can cache an image of the
737      actor. If a parameter of the effect changes then it only needs to
738      redraw the cached image, not the actual actor. The pointer is
739      only valid if is_dirty == TRUE. If the pointer is NULL then the
740      whole actor is dirty. */
741   ClutterEffect *effect_to_redraw;
742
743   /* This is used when painting effects to implement the
744      clutter_actor_continue_paint() function. It points to the node in
745      the list of effects that is next in the chain */
746   const GList *next_effect_to_paint;
747
748   ClutterPaintVolume paint_volume;
749
750   /* NB: This volume isn't relative to this actor, it is in eye
751    * coordinates so that it can remain valid after the actor changes.
752    */
753   ClutterPaintVolume last_paint_volume;
754
755   ClutterStageQueueRedrawEntry *queue_redraw_entry;
756
757   ClutterColor bg_color;
758
759 #ifdef CLUTTER_ENABLE_DEBUG
760   /* a string used for debugging messages */
761   gchar *debug_name;
762 #endif
763
764   /* bitfields */
765
766   /* fixed position and sizes */
767   guint position_set                : 1;
768   guint min_width_set               : 1;
769   guint min_height_set              : 1;
770   guint natural_width_set           : 1;
771   guint natural_height_set          : 1;
772   /* cached request is invalid (implies allocation is too) */
773   guint needs_width_request         : 1;
774   /* cached request is invalid (implies allocation is too) */
775   guint needs_height_request        : 1;
776   /* cached allocation is invalid (request has changed, probably) */
777   guint needs_allocation            : 1;
778   guint show_on_set_parent          : 1;
779   guint has_clip                    : 1;
780   guint clip_to_allocation          : 1;
781   guint enable_model_view_transform : 1;
782   guint enable_paint_unmapped       : 1;
783   guint has_pointer                 : 1;
784   guint propagated_one_redraw       : 1;
785   guint paint_volume_valid          : 1;
786   guint last_paint_volume_valid     : 1;
787   guint in_clone_paint              : 1;
788   guint transform_valid             : 1;
789   /* This is TRUE if anything has queued a redraw since we were last
790      painted. In this case effect_to_redraw will point to an effect
791      the redraw was queued from or it will be NULL if the redraw was
792      queued without an effect. */
793   guint is_dirty                    : 1;
794   guint bg_color_set                : 1;
795   guint content_box_valid           : 1;
796   guint x_expand_set                : 1;
797   guint y_expand_set                : 1;
798   guint needs_compute_expand        : 1;
799   guint needs_x_expand              : 1;
800   guint needs_y_expand              : 1;
801 };
802
803 enum
804 {
805   PROP_0,
806
807   PROP_NAME,
808
809   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
810    * when set they force a size request, when gotten they
811    * get the allocation if the allocation is valid, and the
812    * request otherwise
813    */
814   PROP_X,
815   PROP_Y,
816   PROP_WIDTH,
817   PROP_HEIGHT,
818
819   PROP_POSITION,
820   PROP_SIZE,
821
822   /* Then the rest of these size-related properties are the "actual"
823    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
824    */
825   PROP_FIXED_X,
826   PROP_FIXED_Y,
827
828   PROP_FIXED_POSITION_SET,
829
830   PROP_MIN_WIDTH,
831   PROP_MIN_WIDTH_SET,
832
833   PROP_MIN_HEIGHT,
834   PROP_MIN_HEIGHT_SET,
835
836   PROP_NATURAL_WIDTH,
837   PROP_NATURAL_WIDTH_SET,
838
839   PROP_NATURAL_HEIGHT,
840   PROP_NATURAL_HEIGHT_SET,
841
842   PROP_REQUEST_MODE,
843
844   /* Allocation properties are read-only */
845   PROP_ALLOCATION,
846
847   PROP_DEPTH,
848
849   PROP_CLIP,
850   PROP_HAS_CLIP,
851   PROP_CLIP_TO_ALLOCATION,
852
853   PROP_OPACITY,
854
855   PROP_OFFSCREEN_REDIRECT,
856
857   PROP_VISIBLE,
858   PROP_MAPPED,
859   PROP_REALIZED,
860   PROP_REACTIVE,
861
862   PROP_SCALE_X,
863   PROP_SCALE_Y,
864   PROP_SCALE_CENTER_X,
865   PROP_SCALE_CENTER_Y,
866   PROP_SCALE_GRAVITY,
867
868   PROP_ROTATION_ANGLE_X,
869   PROP_ROTATION_ANGLE_Y,
870   PROP_ROTATION_ANGLE_Z,
871   PROP_ROTATION_CENTER_X,
872   PROP_ROTATION_CENTER_Y,
873   PROP_ROTATION_CENTER_Z,
874   /* This property only makes sense for the z rotation because the
875      others would depend on the actor having a size along the
876      z-axis */
877   PROP_ROTATION_CENTER_Z_GRAVITY,
878
879   PROP_ANCHOR_X,
880   PROP_ANCHOR_Y,
881   PROP_ANCHOR_GRAVITY,
882
883   PROP_SHOW_ON_SET_PARENT,
884
885   PROP_TEXT_DIRECTION,
886   PROP_HAS_POINTER,
887
888   PROP_ACTIONS,
889   PROP_CONSTRAINTS,
890   PROP_EFFECT,
891
892   PROP_LAYOUT_MANAGER,
893
894   PROP_X_EXPAND,
895   PROP_Y_EXPAND,
896   PROP_X_ALIGN,
897   PROP_Y_ALIGN,
898   PROP_MARGIN_TOP,
899   PROP_MARGIN_BOTTOM,
900   PROP_MARGIN_LEFT,
901   PROP_MARGIN_RIGHT,
902
903   PROP_BACKGROUND_COLOR,
904   PROP_BACKGROUND_COLOR_SET,
905
906   PROP_FIRST_CHILD,
907   PROP_LAST_CHILD,
908
909   PROP_CONTENT,
910   PROP_CONTENT_GRAVITY,
911   PROP_CONTENT_BOX,
912   PROP_MINIFICATION_FILTER,
913   PROP_MAGNIFICATION_FILTER,
914   PROP_CONTENT_REPEAT,
915
916   PROP_LAST
917 };
918
919 static GParamSpec *obj_props[PROP_LAST];
920
921 enum
922 {
923   SHOW,
924   HIDE,
925   DESTROY,
926   PARENT_SET,
927   KEY_FOCUS_IN,
928   KEY_FOCUS_OUT,
929   PAINT,
930   PICK,
931   REALIZE,
932   UNREALIZE,
933   QUEUE_REDRAW,
934   QUEUE_RELAYOUT,
935   EVENT,
936   CAPTURED_EVENT,
937   BUTTON_PRESS_EVENT,
938   BUTTON_RELEASE_EVENT,
939   SCROLL_EVENT,
940   KEY_PRESS_EVENT,
941   KEY_RELEASE_EVENT,
942   MOTION_EVENT,
943   ENTER_EVENT,
944   LEAVE_EVENT,
945   ALLOCATION_CHANGED,
946   TRANSITIONS_COMPLETED,
947
948   LAST_SIGNAL
949 };
950
951 static guint actor_signals[LAST_SIGNAL] = { 0, };
952
953 typedef struct _TransitionClosure
954 {
955   ClutterActor *actor;
956   ClutterTransition *transition;
957   gchar *name;
958   gulong completed_id;
959 } TransitionClosure;
960
961 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
962 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
963 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
964 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
965
966 /* These setters are all static for now, maybe they should be in the
967  * public API, but they are perhaps obscure enough to leave only as
968  * properties
969  */
970 static void clutter_actor_set_min_width          (ClutterActor *self,
971                                                   gfloat        min_width);
972 static void clutter_actor_set_min_height         (ClutterActor *self,
973                                                   gfloat        min_height);
974 static void clutter_actor_set_natural_width      (ClutterActor *self,
975                                                   gfloat        natural_width);
976 static void clutter_actor_set_natural_height     (ClutterActor *self,
977                                                   gfloat        natural_height);
978 static void clutter_actor_set_min_width_set      (ClutterActor *self,
979                                                   gboolean      use_min_width);
980 static void clutter_actor_set_min_height_set     (ClutterActor *self,
981                                                   gboolean      use_min_height);
982 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
983                                                   gboolean  use_natural_width);
984 static void clutter_actor_set_natural_height_set (ClutterActor *self,
985                                                   gboolean  use_natural_height);
986 static void clutter_actor_update_map_state       (ClutterActor  *self,
987                                                   MapStateChange change);
988 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
989
990 /* Helper routines for managing anchor coords */
991 static void clutter_anchor_coord_get_units (ClutterActor      *self,
992                                             const AnchorCoord *coord,
993                                             gfloat            *x,
994                                             gfloat            *y,
995                                             gfloat            *z);
996 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
997                                             gfloat             x,
998                                             gfloat             y,
999                                             gfloat             z);
1000
1001 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
1002 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
1003                                                         ClutterGravity     gravity);
1004
1005 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
1006
1007 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1008
1009 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1010                                                                ClutterActor *ancestor,
1011                                                                CoglMatrix *matrix);
1012
1013 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1014
1015 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
1016
1017 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1018                                                                 const ClutterColor *color);
1019
1020 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1021                                        ClutterActor         *self);
1022
1023 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1024
1025 /* Helper macro which translates by the anchor coord, applies the
1026    given transformation and then translates back */
1027 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
1028   gfloat _tx, _ty, _tz;                                                \
1029   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
1030   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1031   { _transform; }                                                      \
1032   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1033
1034 static GQuark quark_shader_data = 0;
1035 static GQuark quark_actor_layout_info = 0;
1036 static GQuark quark_actor_transform_info = 0;
1037 static GQuark quark_actor_animation_info = 0;
1038
1039 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1040                          clutter_actor,
1041                          G_TYPE_INITIALLY_UNOWNED,
1042                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1043                                                 clutter_container_iface_init)
1044                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1045                                                 clutter_scriptable_iface_init)
1046                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1047                                                 clutter_animatable_iface_init)
1048                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1049                                                 atk_implementor_iface_init));
1050
1051 /*< private >
1052  * clutter_actor_get_debug_name:
1053  * @actor: a #ClutterActor
1054  *
1055  * Retrieves a printable name of @actor for debugging messages
1056  *
1057  * Return value: a string with a printable name
1058  */
1059 const gchar *
1060 _clutter_actor_get_debug_name (ClutterActor *actor)
1061 {
1062   ClutterActorPrivate *priv = actor->priv;
1063   const gchar *retval;
1064
1065 #ifdef CLUTTER_ENABLE_DEBUG
1066   if (G_UNLIKELY (priv->debug_name == NULL))
1067     {
1068       priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]",
1069                                           priv->name != NULL ? priv->name
1070                                                              : "unnamed",
1071                                           G_OBJECT_TYPE_NAME (actor),
1072                                           actor);
1073     }
1074
1075   retval = priv->debug_name;
1076 #else
1077   retval = priv->name != NULL
1078          ? priv->name
1079          : G_OBJECT_TYPE_NAME (actor);
1080 #endif
1081
1082   return retval;
1083 }
1084
1085 #ifdef CLUTTER_ENABLE_DEBUG
1086 /* XXX - this is for debugging only, remove once working (or leave
1087  * in only in some debug mode). Should leave it for a little while
1088  * until we're confident in the new map/realize/visible handling.
1089  */
1090 static inline void
1091 clutter_actor_verify_map_state (ClutterActor *self)
1092 {
1093   ClutterActorPrivate *priv = self->priv;
1094
1095   if (CLUTTER_ACTOR_IS_REALIZED (self))
1096     {
1097       /* all bets are off during reparent when we're potentially realized,
1098        * but should not be according to invariants
1099        */
1100       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1101         {
1102           if (priv->parent == NULL)
1103             {
1104               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1105                 {
1106                 }
1107               else
1108                 g_warning ("Realized non-toplevel actor '%s' should "
1109                            "have a parent",
1110                            _clutter_actor_get_debug_name (self));
1111             }
1112           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1113             {
1114               g_warning ("Realized actor %s has an unrealized parent %s",
1115                          _clutter_actor_get_debug_name (self),
1116                          _clutter_actor_get_debug_name (priv->parent));
1117             }
1118         }
1119     }
1120
1121   if (CLUTTER_ACTOR_IS_MAPPED (self))
1122     {
1123       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1124         g_warning ("Actor '%s' is mapped but not realized",
1125                    _clutter_actor_get_debug_name (self));
1126
1127       /* remaining bets are off during reparent when we're potentially
1128        * mapped, but should not be according to invariants
1129        */
1130       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1131         {
1132           if (priv->parent == NULL)
1133             {
1134               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1135                 {
1136                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1137                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1138                     {
1139                       g_warning ("Toplevel actor '%s' is mapped "
1140                                  "but not visible",
1141                                  _clutter_actor_get_debug_name (self));
1142                     }
1143                 }
1144               else
1145                 {
1146                   g_warning ("Mapped actor '%s' should have a parent",
1147                              _clutter_actor_get_debug_name (self));
1148                 }
1149             }
1150           else
1151             {
1152               ClutterActor *iter = self;
1153
1154               /* check for the enable_paint_unmapped flag on the actor
1155                * and parents; if the flag is enabled at any point of this
1156                * branch of the scene graph then all the later checks
1157                * become pointless
1158                */
1159               while (iter != NULL)
1160                 {
1161                   if (iter->priv->enable_paint_unmapped)
1162                     return;
1163
1164                   iter = iter->priv->parent;
1165                 }
1166
1167               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1168                 {
1169                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1170                              "is not visible",
1171                              _clutter_actor_get_debug_name (self),
1172                              _clutter_actor_get_debug_name (priv->parent));
1173                 }
1174
1175               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1176                 {
1177                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1178                              "is not realized",
1179                              _clutter_actor_get_debug_name (self),
1180                              _clutter_actor_get_debug_name (priv->parent));
1181                 }
1182
1183               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1184                 {
1185                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1186                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1187                                "parent '%s' is not mapped",
1188                                _clutter_actor_get_debug_name (self),
1189                                _clutter_actor_get_debug_name (priv->parent));
1190                 }
1191             }
1192         }
1193     }
1194 }
1195
1196 #endif /* CLUTTER_ENABLE_DEBUG */
1197
1198 static void
1199 clutter_actor_set_mapped (ClutterActor *self,
1200                           gboolean      mapped)
1201 {
1202   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1203     return;
1204
1205   if (mapped)
1206     {
1207       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1208       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1209     }
1210   else
1211     {
1212       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1213       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1214     }
1215 }
1216
1217 /* this function updates the mapped and realized states according to
1218  * invariants, in the appropriate order.
1219  */
1220 static void
1221 clutter_actor_update_map_state (ClutterActor  *self,
1222                                 MapStateChange change)
1223 {
1224   gboolean was_mapped;
1225
1226   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1227
1228   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1229     {
1230       /* the mapped flag on top-level actors must be set by the
1231        * per-backend implementation because it might be asynchronous.
1232        *
1233        * That is, the MAPPED flag on toplevels currently tracks the X
1234        * server mapped-ness of the window, while the expected behavior
1235        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1236        * This creates some weird complexity by breaking the invariant
1237        * that if we're visible and all ancestors shown then we are
1238        * also mapped - instead, we are mapped if all ancestors
1239        * _possibly excepting_ the stage are mapped. The stage
1240        * will map/unmap for example when it is minimized or
1241        * moved to another workspace.
1242        *
1243        * So, the only invariant on the stage is that if visible it
1244        * should be realized, and that it has to be visible to be
1245        * mapped.
1246        */
1247       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1248         clutter_actor_realize (self);
1249
1250       switch (change)
1251         {
1252         case MAP_STATE_CHECK:
1253           break;
1254
1255         case MAP_STATE_MAKE_MAPPED:
1256           g_assert (!was_mapped);
1257           clutter_actor_set_mapped (self, TRUE);
1258           break;
1259
1260         case MAP_STATE_MAKE_UNMAPPED:
1261           g_assert (was_mapped);
1262           clutter_actor_set_mapped (self, FALSE);
1263           break;
1264
1265         case MAP_STATE_MAKE_UNREALIZED:
1266           /* we only use MAKE_UNREALIZED in unparent,
1267            * and unparenting a stage isn't possible.
1268            * If someone wants to just unrealize a stage
1269            * then clutter_actor_unrealize() doesn't
1270            * go through this codepath.
1271            */
1272           g_warning ("Trying to force unrealize stage is not allowed");
1273           break;
1274         }
1275
1276       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1277           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1278           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1279         {
1280           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1281                      "it is somehow still mapped",
1282                      _clutter_actor_get_debug_name (self));
1283         }
1284     }
1285   else
1286     {
1287       ClutterActorPrivate *priv = self->priv;
1288       ClutterActor *parent = priv->parent;
1289       gboolean should_be_mapped;
1290       gboolean may_be_realized;
1291       gboolean must_be_realized;
1292
1293       should_be_mapped = FALSE;
1294       may_be_realized = TRUE;
1295       must_be_realized = FALSE;
1296
1297       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1298         {
1299           may_be_realized = FALSE;
1300         }
1301       else
1302         {
1303           /* Maintain invariant that if parent is mapped, and we are
1304            * visible, then we are mapped ...  unless parent is a
1305            * stage, in which case we map regardless of parent's map
1306            * state but do require stage to be visible and realized.
1307            *
1308            * If parent is realized, that does not force us to be
1309            * realized; but if parent is unrealized, that does force
1310            * us to be unrealized.
1311            *
1312            * The reason we don't force children to realize with
1313            * parents is _clutter_actor_rerealize(); if we require that
1314            * a realized parent means children are realized, then to
1315            * unrealize an actor we would have to unrealize its
1316            * parents, which would end up meaning unrealizing and
1317            * hiding the entire stage. So we allow unrealizing a
1318            * child (as long as that child is not mapped) while that
1319            * child still has a realized parent.
1320            *
1321            * Also, if we unrealize from leaf nodes to root, and
1322            * realize from root to leaf, the invariants are never
1323            * violated if we allow children to be unrealized
1324            * while parents are realized.
1325            *
1326            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1327            * to force us to unmap, even though parent is still
1328            * mapped. This is because we're unmapping from leaf nodes
1329            * up to root nodes.
1330            */
1331           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1332               change != MAP_STATE_MAKE_UNMAPPED)
1333             {
1334               gboolean parent_is_visible_realized_toplevel;
1335
1336               parent_is_visible_realized_toplevel =
1337                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1338                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1339                  CLUTTER_ACTOR_IS_REALIZED (parent));
1340
1341               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1342                   parent_is_visible_realized_toplevel)
1343                 {
1344                   must_be_realized = TRUE;
1345                   should_be_mapped = TRUE;
1346                 }
1347             }
1348
1349           /* if the actor has been set to be painted even if unmapped
1350            * then we should map it and check for realization as well;
1351            * this is an override for the branch of the scene graph
1352            * which begins with this node
1353            */
1354           if (priv->enable_paint_unmapped)
1355             {
1356               if (priv->parent == NULL)
1357                 g_warning ("Attempting to map an unparented actor '%s'",
1358                            _clutter_actor_get_debug_name (self));
1359
1360               should_be_mapped = TRUE;
1361               must_be_realized = TRUE;
1362             }
1363
1364           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1365             may_be_realized = FALSE;
1366         }
1367
1368       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1369         {
1370           if (parent == NULL)
1371             g_warning ("Attempting to map a child that does not "
1372                        "meet the necessary invariants: the actor '%s' "
1373                        "has no parent",
1374                        _clutter_actor_get_debug_name (self));
1375           else
1376             g_warning ("Attempting to map a child that does not "
1377                        "meet the necessary invariants: the actor '%s' "
1378                        "is parented to an unmapped actor '%s'",
1379                        _clutter_actor_get_debug_name (self),
1380                        _clutter_actor_get_debug_name (priv->parent));
1381         }
1382
1383       /* If in reparent, we temporarily suspend unmap and unrealize.
1384        *
1385        * We want to go in the order "realize, map" and "unmap, unrealize"
1386        */
1387
1388       /* Unmap */
1389       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1390         clutter_actor_set_mapped (self, FALSE);
1391
1392       /* Realize */
1393       if (must_be_realized)
1394         clutter_actor_realize (self);
1395
1396       /* if we must be realized then we may be, presumably */
1397       g_assert (!(must_be_realized && !may_be_realized));
1398
1399       /* Unrealize */
1400       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1401         clutter_actor_unrealize_not_hiding (self);
1402
1403       /* Map */
1404       if (should_be_mapped)
1405         {
1406           if (!must_be_realized)
1407             g_warning ("Somehow we think actor '%s' should be mapped but "
1408                        "not realized, which isn't allowed",
1409                        _clutter_actor_get_debug_name (self));
1410
1411           /* realization is allowed to fail (though I don't know what
1412            * an app is supposed to do about that - shouldn't it just
1413            * be a g_error? anyway, we have to avoid mapping if this
1414            * happens)
1415            */
1416           if (CLUTTER_ACTOR_IS_REALIZED (self))
1417             clutter_actor_set_mapped (self, TRUE);
1418         }
1419     }
1420
1421 #ifdef CLUTTER_ENABLE_DEBUG
1422   /* check all invariants were kept */
1423   clutter_actor_verify_map_state (self);
1424 #endif
1425 }
1426
1427 static void
1428 clutter_actor_real_map (ClutterActor *self)
1429 {
1430   ClutterActorPrivate *priv = self->priv;
1431   ClutterActor *stage, *iter;
1432
1433   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1434
1435   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1436                 _clutter_actor_get_debug_name (self));
1437
1438   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1439
1440   stage = _clutter_actor_get_stage_internal (self);
1441   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1442
1443   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1444                 priv->pick_id,
1445                 _clutter_actor_get_debug_name (self));
1446
1447   /* notify on parent mapped before potentially mapping
1448    * children, so apps see a top-down notification.
1449    */
1450   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1451
1452   for (iter = self->priv->first_child;
1453        iter != NULL;
1454        iter = iter->priv->next_sibling)
1455     {
1456       clutter_actor_map (iter);
1457     }
1458 }
1459
1460 /**
1461  * clutter_actor_map:
1462  * @self: A #ClutterActor
1463  *
1464  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1465  * and realizes its children if they are visible. Does nothing if the
1466  * actor is not visible.
1467  *
1468  * Calling this function is strongly disencouraged: the default
1469  * implementation of #ClutterActorClass.map() will map all the children
1470  * of an actor when mapping its parent.
1471  *
1472  * When overriding map, it is mandatory to chain up to the parent
1473  * implementation.
1474  *
1475  * Since: 1.0
1476  */
1477 void
1478 clutter_actor_map (ClutterActor *self)
1479 {
1480   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1481
1482   if (CLUTTER_ACTOR_IS_MAPPED (self))
1483     return;
1484
1485   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1486     return;
1487
1488   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1489 }
1490
1491 static void
1492 clutter_actor_real_unmap (ClutterActor *self)
1493 {
1494   ClutterActorPrivate *priv = self->priv;
1495   ClutterActor *iter;
1496
1497   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1498
1499   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1500                 _clutter_actor_get_debug_name (self));
1501
1502   for (iter = self->priv->first_child;
1503        iter != NULL;
1504        iter = iter->priv->next_sibling)
1505     {
1506       clutter_actor_unmap (iter);
1507     }
1508
1509   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1510
1511   /* clear the contents of the last paint volume, so that hiding + moving +
1512    * showing will not result in the wrong area being repainted
1513    */
1514   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1515   priv->last_paint_volume_valid = TRUE;
1516
1517   /* notify on parent mapped after potentially unmapping
1518    * children, so apps see a bottom-up notification.
1519    */
1520   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1521
1522   /* relinquish keyboard focus if we were unmapped while owning it */
1523   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1524     {
1525       ClutterStage *stage;
1526
1527       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1528
1529       if (stage != NULL)
1530         _clutter_stage_release_pick_id (stage, priv->pick_id);
1531
1532       priv->pick_id = -1;
1533
1534       if (stage != NULL &&
1535           clutter_stage_get_key_focus (stage) == self)
1536         {
1537           clutter_stage_set_key_focus (stage, NULL);
1538         }
1539     }
1540 }
1541
1542 /**
1543  * clutter_actor_unmap:
1544  * @self: A #ClutterActor
1545  *
1546  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1547  * unmaps its children if they were mapped.
1548  *
1549  * Calling this function is not encouraged: the default #ClutterActor
1550  * implementation of #ClutterActorClass.unmap() will also unmap any
1551  * eventual children by default when their parent is unmapped.
1552  *
1553  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1554  * chain up to the parent implementation.
1555  *
1556  * <note>It is important to note that the implementation of the
1557  * #ClutterActorClass.unmap() virtual function may be called after
1558  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1559  * implementation, but it is guaranteed to be called before the
1560  * #GObjectClass.finalize() implementation.</note>
1561  *
1562  * Since: 1.0
1563  */
1564 void
1565 clutter_actor_unmap (ClutterActor *self)
1566 {
1567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1568
1569   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1570     return;
1571
1572   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1573 }
1574
1575 static void
1576 clutter_actor_real_show (ClutterActor *self)
1577 {
1578   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1579     {
1580       ClutterActorPrivate *priv = self->priv;
1581
1582       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1583
1584       /* we notify on the "visible" flag in the clutter_actor_show()
1585        * wrapper so the entire show signal emission completes first
1586        * (?)
1587        */
1588       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1589
1590       /* we queue a relayout unless the actor is inside a
1591        * container that explicitly told us not to
1592        */
1593       if (priv->parent != NULL &&
1594           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1595         {
1596           /* While an actor is hidden the parent may not have
1597            * allocated/requested so we need to start from scratch
1598            * and avoid the short-circuiting in
1599            * clutter_actor_queue_relayout().
1600            */
1601           priv->needs_width_request  = FALSE;
1602           priv->needs_height_request = FALSE;
1603           priv->needs_allocation     = FALSE;
1604           clutter_actor_queue_relayout (self);
1605         }
1606     }
1607 }
1608
1609 static inline void
1610 set_show_on_set_parent (ClutterActor *self,
1611                         gboolean      set_show)
1612 {
1613   ClutterActorPrivate *priv = self->priv;
1614
1615   set_show = !!set_show;
1616
1617   if (priv->show_on_set_parent == set_show)
1618     return;
1619
1620   if (priv->parent == NULL)
1621     {
1622       priv->show_on_set_parent = set_show;
1623       g_object_notify_by_pspec (G_OBJECT (self),
1624                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1625     }
1626 }
1627
1628 /**
1629  * clutter_actor_show:
1630  * @self: A #ClutterActor
1631  *
1632  * Flags an actor to be displayed. An actor that isn't shown will not
1633  * be rendered on the stage.
1634  *
1635  * Actors are visible by default.
1636  *
1637  * If this function is called on an actor without a parent, the
1638  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1639  * effect.
1640  */
1641 void
1642 clutter_actor_show (ClutterActor *self)
1643 {
1644   ClutterActorPrivate *priv;
1645
1646   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1647
1648   /* simple optimization */
1649   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1650     {
1651       /* we still need to set the :show-on-set-parent property, in
1652        * case show() is called on an unparented actor
1653        */
1654       set_show_on_set_parent (self, TRUE);
1655       return;
1656     }
1657
1658 #ifdef CLUTTER_ENABLE_DEBUG
1659   clutter_actor_verify_map_state (self);
1660 #endif
1661
1662   priv = self->priv;
1663
1664   g_object_freeze_notify (G_OBJECT (self));
1665
1666   set_show_on_set_parent (self, TRUE);
1667
1668   /* if we're showing a child that needs to expand, or may
1669    * expand, then we need to recompute the expand flags for
1670    * its parent as well
1671    */
1672   if (priv->needs_compute_expand ||
1673       priv->needs_x_expand ||
1674       priv->needs_y_expand)
1675     {
1676       clutter_actor_queue_compute_expand (self);
1677     }
1678
1679   g_signal_emit (self, actor_signals[SHOW], 0);
1680   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1681
1682   if (priv->parent != NULL)
1683     clutter_actor_queue_redraw (priv->parent);
1684
1685   g_object_thaw_notify (G_OBJECT (self));
1686 }
1687
1688 /**
1689  * clutter_actor_show_all:
1690  * @self: a #ClutterActor
1691  *
1692  * Calls clutter_actor_show() on all children of an actor (if any).
1693  *
1694  * Since: 0.2
1695  *
1696  * Deprecated: 1.10: Actors are visible by default
1697  */
1698 void
1699 clutter_actor_show_all (ClutterActor *self)
1700 {
1701   ClutterActorClass *klass;
1702
1703   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1704
1705   klass = CLUTTER_ACTOR_GET_CLASS (self);
1706   if (klass->show_all)
1707     klass->show_all (self);
1708 }
1709
1710 static void
1711 clutter_actor_real_hide (ClutterActor *self)
1712 {
1713   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1714     {
1715       ClutterActorPrivate *priv = self->priv;
1716
1717       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1718
1719       /* we notify on the "visible" flag in the clutter_actor_hide()
1720        * wrapper so the entire hide signal emission completes first
1721        * (?)
1722        */
1723       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1724
1725       /* we queue a relayout unless the actor is inside a
1726        * container that explicitly told us not to
1727        */
1728       if (priv->parent != NULL &&
1729           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1730         clutter_actor_queue_relayout (priv->parent);
1731     }
1732 }
1733
1734 /**
1735  * clutter_actor_hide:
1736  * @self: A #ClutterActor
1737  *
1738  * Flags an actor to be hidden. A hidden actor will not be
1739  * rendered on the stage.
1740  *
1741  * Actors are visible by default.
1742  *
1743  * If this function is called on an actor without a parent, the
1744  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1745  * as a side-effect.
1746  */
1747 void
1748 clutter_actor_hide (ClutterActor *self)
1749 {
1750   ClutterActorPrivate *priv;
1751
1752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1753
1754   /* simple optimization */
1755   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1756     {
1757       /* we still need to set the :show-on-set-parent property, in
1758        * case hide() is called on an unparented actor
1759        */
1760       set_show_on_set_parent (self, FALSE);
1761       return;
1762     }
1763
1764 #ifdef CLUTTER_ENABLE_DEBUG
1765   clutter_actor_verify_map_state (self);
1766 #endif
1767
1768   priv = self->priv;
1769
1770   g_object_freeze_notify (G_OBJECT (self));
1771
1772   set_show_on_set_parent (self, FALSE);
1773
1774   /* if we're hiding a child that needs to expand, or may
1775    * expand, then we need to recompute the expand flags for
1776    * its parent as well
1777    */
1778   if (priv->needs_compute_expand ||
1779       priv->needs_x_expand ||
1780       priv->needs_y_expand)
1781     {
1782       clutter_actor_queue_compute_expand (self);
1783     }
1784
1785   g_signal_emit (self, actor_signals[HIDE], 0);
1786   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1787
1788   if (priv->parent != NULL)
1789     clutter_actor_queue_redraw (priv->parent);
1790
1791   g_object_thaw_notify (G_OBJECT (self));
1792 }
1793
1794 /**
1795  * clutter_actor_hide_all:
1796  * @self: a #ClutterActor
1797  *
1798  * Calls clutter_actor_hide() on all child actors (if any).
1799  *
1800  * Since: 0.2
1801  *
1802  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1803  *   prevent its children from being painted as well.
1804  */
1805 void
1806 clutter_actor_hide_all (ClutterActor *self)
1807 {
1808   ClutterActorClass *klass;
1809
1810   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1811
1812   klass = CLUTTER_ACTOR_GET_CLASS (self);
1813   if (klass->hide_all)
1814     klass->hide_all (self);
1815 }
1816
1817 /**
1818  * clutter_actor_realize:
1819  * @self: A #ClutterActor
1820  *
1821  * Realization informs the actor that it is attached to a stage. It
1822  * can use this to allocate resources if it wanted to delay allocation
1823  * until it would be rendered. However it is perfectly acceptable for
1824  * an actor to create resources before being realized because Clutter
1825  * only ever has a single rendering context so that actor is free to
1826  * be moved from one stage to another.
1827  *
1828  * This function does nothing if the actor is already realized.
1829  *
1830  * Because a realized actor must have realized parent actors, calling
1831  * clutter_actor_realize() will also realize all parents of the actor.
1832  *
1833  * This function does not realize child actors, except in the special
1834  * case that realizing the stage, when the stage is visible, will
1835  * suddenly map (and thus realize) the children of the stage.
1836  **/
1837 void
1838 clutter_actor_realize (ClutterActor *self)
1839 {
1840   ClutterActorPrivate *priv;
1841
1842   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1843
1844   priv = self->priv;
1845
1846 #ifdef CLUTTER_ENABLE_DEBUG
1847   clutter_actor_verify_map_state (self);
1848 #endif
1849
1850   if (CLUTTER_ACTOR_IS_REALIZED (self))
1851     return;
1852
1853   /* To be realized, our parent actors must be realized first.
1854    * This will only succeed if we're inside a toplevel.
1855    */
1856   if (priv->parent != NULL)
1857     clutter_actor_realize (priv->parent);
1858
1859   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1860     {
1861       /* toplevels can be realized at any time */
1862     }
1863   else
1864     {
1865       /* "Fail" the realization if parent is missing or unrealized;
1866        * this should really be a g_warning() not some kind of runtime
1867        * failure; how can an app possibly recover? Instead it's a bug
1868        * in the app and the app should get an explanatory warning so
1869        * someone can fix it. But for now it's too hard to fix this
1870        * because e.g. ClutterTexture needs reworking.
1871        */
1872       if (priv->parent == NULL ||
1873           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1874         return;
1875     }
1876
1877   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1878
1879   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1880   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1881
1882   g_signal_emit (self, actor_signals[REALIZE], 0);
1883
1884   /* Stage actor is allowed to unset the realized flag again in its
1885    * default signal handler, though that is a pathological situation.
1886    */
1887
1888   /* If realization "failed" we'll have to update child state. */
1889   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1890 }
1891
1892 static void
1893 clutter_actor_real_unrealize (ClutterActor *self)
1894 {
1895   /* we must be unmapped (implying our children are also unmapped) */
1896   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1897 }
1898
1899 /**
1900  * clutter_actor_unrealize:
1901  * @self: A #ClutterActor
1902  *
1903  * Unrealization informs the actor that it may be being destroyed or
1904  * moved to another stage. The actor may want to destroy any
1905  * underlying graphics resources at this point. However it is
1906  * perfectly acceptable for it to retain the resources until the actor
1907  * is destroyed because Clutter only ever uses a single rendering
1908  * context and all of the graphics resources are valid on any stage.
1909  *
1910  * Because mapped actors must be realized, actors may not be
1911  * unrealized if they are mapped. This function hides the actor to be
1912  * sure it isn't mapped, an application-visible side effect that you
1913  * may not be expecting.
1914  *
1915  * This function should not be called by application code.
1916  */
1917 void
1918 clutter_actor_unrealize (ClutterActor *self)
1919 {
1920   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1921   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1922
1923 /* This function should not really be in the public API, because
1924  * there isn't a good reason to call it. ClutterActor will already
1925  * unrealize things for you when it's important to do so.
1926  *
1927  * If you were using clutter_actor_unrealize() in a dispose
1928  * implementation, then don't, just chain up to ClutterActor's
1929  * dispose.
1930  *
1931  * If you were using clutter_actor_unrealize() to implement
1932  * unrealizing children of your container, then don't, ClutterActor
1933  * will already take care of that.
1934  *
1935  * If you were using clutter_actor_unrealize() to re-realize to
1936  * create your resources in a different way, then use
1937  * _clutter_actor_rerealize() (inside Clutter) or just call your
1938  * code that recreates your resources directly (outside Clutter).
1939  */
1940
1941 #ifdef CLUTTER_ENABLE_DEBUG
1942   clutter_actor_verify_map_state (self);
1943 #endif
1944
1945   clutter_actor_hide (self);
1946
1947   clutter_actor_unrealize_not_hiding (self);
1948 }
1949
1950 static ClutterActorTraverseVisitFlags
1951 unrealize_actor_before_children_cb (ClutterActor *self,
1952                                     int depth,
1953                                     void *user_data)
1954 {
1955   /* If an actor is already unrealized we know its children have also
1956    * already been unrealized... */
1957   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1958     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1959
1960   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1961
1962   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1963 }
1964
1965 static ClutterActorTraverseVisitFlags
1966 unrealize_actor_after_children_cb (ClutterActor *self,
1967                                    int depth,
1968                                    void *user_data)
1969 {
1970   /* We want to unset the realized flag only _after_
1971    * child actors are unrealized, to maintain invariants.
1972    */
1973   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1974   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1975   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1976 }
1977
1978 /*
1979  * clutter_actor_unrealize_not_hiding:
1980  * @self: A #ClutterActor
1981  *
1982  * Unrealization informs the actor that it may be being destroyed or
1983  * moved to another stage. The actor may want to destroy any
1984  * underlying graphics resources at this point. However it is
1985  * perfectly acceptable for it to retain the resources until the actor
1986  * is destroyed because Clutter only ever uses a single rendering
1987  * context and all of the graphics resources are valid on any stage.
1988  *
1989  * Because mapped actors must be realized, actors may not be
1990  * unrealized if they are mapped. You must hide the actor or one of
1991  * its parents before attempting to unrealize.
1992  *
1993  * This function is separate from clutter_actor_unrealize() because it
1994  * does not automatically hide the actor.
1995  * Actors need not be hidden to be unrealized, they just need to
1996  * be unmapped. In fact we don't want to mess up the application's
1997  * setting of the "visible" flag, so hiding is very undesirable.
1998  *
1999  * clutter_actor_unrealize() does a clutter_actor_hide() just for
2000  * backward compatibility.
2001  */
2002 static void
2003 clutter_actor_unrealize_not_hiding (ClutterActor *self)
2004 {
2005   _clutter_actor_traverse (self,
2006                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
2007                            unrealize_actor_before_children_cb,
2008                            unrealize_actor_after_children_cb,
2009                            NULL);
2010 }
2011
2012 /*
2013  * _clutter_actor_rerealize:
2014  * @self: A #ClutterActor
2015  * @callback: Function to call while unrealized
2016  * @data: data for callback
2017  *
2018  * If an actor is already unrealized, this just calls the callback.
2019  *
2020  * If it is realized, it unrealizes temporarily, calls the callback,
2021  * and then re-realizes the actor.
2022  *
2023  * As a side effect, leaves all children of the actor unrealized if
2024  * the actor was realized but not showing.  This is because when we
2025  * unrealize the actor temporarily we must unrealize its children
2026  * (e.g. children of a stage can't be realized if stage window is
2027  * gone). And we aren't clever enough to save the realization state of
2028  * all children. In most cases this should not matter, because
2029  * the children will automatically realize when they next become mapped.
2030  */
2031 void
2032 _clutter_actor_rerealize (ClutterActor    *self,
2033                           ClutterCallback  callback,
2034                           void            *data)
2035 {
2036   gboolean was_mapped;
2037   gboolean was_showing;
2038   gboolean was_realized;
2039
2040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2041
2042 #ifdef CLUTTER_ENABLE_DEBUG
2043   clutter_actor_verify_map_state (self);
2044 #endif
2045
2046   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2047   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2048   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2049
2050   /* Must be unmapped to unrealize. Note we only have to hide this
2051    * actor if it was mapped (if all parents were showing).  If actor
2052    * is merely visible (but not mapped), then that's fine, we can
2053    * leave it visible.
2054    */
2055   if (was_mapped)
2056     clutter_actor_hide (self);
2057
2058   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2059
2060   /* unrealize self and all children */
2061   clutter_actor_unrealize_not_hiding (self);
2062
2063   if (callback != NULL)
2064     {
2065       (* callback) (self, data);
2066     }
2067
2068   if (was_showing)
2069     clutter_actor_show (self); /* will realize only if mapping implies it */
2070   else if (was_realized)
2071     clutter_actor_realize (self); /* realize self and all parents */
2072 }
2073
2074 static void
2075 clutter_actor_real_pick (ClutterActor       *self,
2076                          const ClutterColor *color)
2077 {
2078   /* the default implementation is just to paint a rectangle
2079    * with the same size of the actor using the passed color
2080    */
2081   if (clutter_actor_should_pick_paint (self))
2082     {
2083       ClutterActorBox box = { 0, };
2084       float width, height;
2085
2086       clutter_actor_get_allocation_box (self, &box);
2087
2088       width = box.x2 - box.x1;
2089       height = box.y2 - box.y1;
2090
2091       cogl_set_source_color4ub (color->red,
2092                                 color->green,
2093                                 color->blue,
2094                                 color->alpha);
2095
2096       cogl_rectangle (0, 0, width, height);
2097     }
2098
2099   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2100    * with existing container classes that override the pick() virtual
2101    * and chain up to the default implementation - otherwise we'll end up
2102    * painting our children twice.
2103    *
2104    * this has to go away for 2.0; hopefully along the pick() itself.
2105    */
2106   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2107     {
2108       ClutterActor *iter;
2109
2110       for (iter = self->priv->first_child;
2111            iter != NULL;
2112            iter = iter->priv->next_sibling)
2113         clutter_actor_paint (iter);
2114     }
2115 }
2116
2117 /**
2118  * clutter_actor_should_pick_paint:
2119  * @self: A #ClutterActor
2120  *
2121  * Should be called inside the implementation of the
2122  * #ClutterActor::pick virtual function in order to check whether
2123  * the actor should paint itself in pick mode or not.
2124  *
2125  * This function should never be called directly by applications.
2126  *
2127  * Return value: %TRUE if the actor should paint its silhouette,
2128  *   %FALSE otherwise
2129  */
2130 gboolean
2131 clutter_actor_should_pick_paint (ClutterActor *self)
2132 {
2133   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2134
2135   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2136       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2137        CLUTTER_ACTOR_IS_REACTIVE (self)))
2138     return TRUE;
2139
2140   return FALSE;
2141 }
2142
2143 static void
2144 clutter_actor_real_get_preferred_width (ClutterActor *self,
2145                                         gfloat        for_height,
2146                                         gfloat       *min_width_p,
2147                                         gfloat       *natural_width_p)
2148 {
2149   ClutterActorPrivate *priv = self->priv;
2150
2151   if (priv->n_children != 0 &&
2152       priv->layout_manager != NULL)
2153     {
2154       ClutterContainer *container = CLUTTER_CONTAINER (self);
2155
2156       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2157                     "for the preferred width",
2158                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2159                     priv->layout_manager);
2160
2161       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2162                                                   container,
2163                                                   for_height,
2164                                                   min_width_p,
2165                                                   natural_width_p);
2166
2167       return;
2168     }
2169
2170   /* Default implementation is always 0x0, usually an actor
2171    * using this default is relying on someone to set the
2172    * request manually
2173    */
2174   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2175
2176   if (min_width_p)
2177     *min_width_p = 0;
2178
2179   if (natural_width_p)
2180     *natural_width_p = 0;
2181 }
2182
2183 static void
2184 clutter_actor_real_get_preferred_height (ClutterActor *self,
2185                                          gfloat        for_width,
2186                                          gfloat       *min_height_p,
2187                                          gfloat       *natural_height_p)
2188 {
2189   ClutterActorPrivate *priv = self->priv;
2190
2191   if (priv->n_children != 0 &&
2192       priv->layout_manager != NULL)
2193     {
2194       ClutterContainer *container = CLUTTER_CONTAINER (self);
2195
2196       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2197                     "for the preferred height",
2198                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2199                     priv->layout_manager);
2200
2201       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2202                                                    container,
2203                                                    for_width,
2204                                                    min_height_p,
2205                                                    natural_height_p);
2206
2207       return;
2208     }
2209   /* Default implementation is always 0x0, usually an actor
2210    * using this default is relying on someone to set the
2211    * request manually
2212    */
2213   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2214
2215   if (min_height_p)
2216     *min_height_p = 0;
2217
2218   if (natural_height_p)
2219     *natural_height_p = 0;
2220 }
2221
2222 static void
2223 clutter_actor_store_old_geometry (ClutterActor    *self,
2224                                   ClutterActorBox *box)
2225 {
2226   *box = self->priv->allocation;
2227 }
2228
2229 static inline void
2230 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2231                                           const ClutterActorBox *old)
2232 {
2233   ClutterActorPrivate *priv = self->priv;
2234   GObject *obj = G_OBJECT (self);
2235
2236   g_object_freeze_notify (obj);
2237
2238   /* to avoid excessive requisition or allocation cycles we
2239    * use the cached values.
2240    *
2241    * - if we don't have an allocation we assume that we need
2242    *   to notify anyway
2243    * - if we don't have a width or a height request we notify
2244    *   width and height
2245    * - if we have a valid allocation then we check the old
2246    *   bounding box with the current allocation and we notify
2247    *   the changes
2248    */
2249   if (priv->needs_allocation)
2250     {
2251       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2252       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2253       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2254       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2255       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2256       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2257     }
2258   else if (priv->needs_width_request || priv->needs_height_request)
2259     {
2260       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2261       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2262       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2263     }
2264   else
2265     {
2266       gfloat x, y;
2267       gfloat width, height;
2268
2269       x = priv->allocation.x1;
2270       y = priv->allocation.y1;
2271       width = priv->allocation.x2 - priv->allocation.x1;
2272       height = priv->allocation.y2 - priv->allocation.y1;
2273
2274       if (x != old->x1)
2275         {
2276           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2277           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2278         }
2279
2280       if (y != old->y1)
2281         {
2282           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2283           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2284         }
2285
2286       if (width != (old->x2 - old->x1))
2287         {
2288           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2289           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2290         }
2291
2292       if (height != (old->y2 - old->y1))
2293         {
2294           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2295           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2296         }
2297     }
2298
2299   g_object_thaw_notify (obj);
2300 }
2301
2302 /*< private >
2303  * clutter_actor_set_allocation_internal:
2304  * @self: a #ClutterActor
2305  * @box: a #ClutterActorBox
2306  * @flags: allocation flags
2307  *
2308  * Stores the allocation of @self.
2309  *
2310  * This function only performs basic storage and property notification.
2311  *
2312  * This function should be called by clutter_actor_set_allocation()
2313  * and by the default implementation of #ClutterActorClass.allocate().
2314  *
2315  * Return value: %TRUE if the allocation of the #ClutterActor has been
2316  *   changed, and %FALSE otherwise
2317  */
2318 static inline gboolean
2319 clutter_actor_set_allocation_internal (ClutterActor           *self,
2320                                        const ClutterActorBox  *box,
2321                                        ClutterAllocationFlags  flags)
2322 {
2323   ClutterActorPrivate *priv = self->priv;
2324   GObject *obj;
2325   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2326   gboolean retval;
2327   ClutterActorBox old_alloc = { 0, };
2328
2329   obj = G_OBJECT (self);
2330
2331   g_object_freeze_notify (obj);
2332
2333   clutter_actor_store_old_geometry (self, &old_alloc);
2334
2335   x1_changed = priv->allocation.x1 != box->x1;
2336   y1_changed = priv->allocation.y1 != box->y1;
2337   x2_changed = priv->allocation.x2 != box->x2;
2338   y2_changed = priv->allocation.y2 != box->y2;
2339
2340   priv->allocation = *box;
2341   priv->allocation_flags = flags;
2342
2343   /* allocation is authoritative */
2344   priv->needs_width_request = FALSE;
2345   priv->needs_height_request = FALSE;
2346   priv->needs_allocation = FALSE;
2347
2348   if (x1_changed ||
2349       y1_changed ||
2350       x2_changed ||
2351       y2_changed)
2352     {
2353       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2354                     _clutter_actor_get_debug_name (self));
2355
2356       priv->transform_valid = FALSE;
2357
2358       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2359
2360       /* if the allocation changes, so does the content box */
2361       if (priv->content != NULL)
2362         {
2363           priv->content_box_valid = FALSE;
2364           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2365         }
2366
2367       retval = TRUE;
2368     }
2369   else
2370     retval = FALSE;
2371
2372   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2373
2374   g_object_thaw_notify (obj);
2375
2376   return retval;
2377 }
2378
2379 static void clutter_actor_real_allocate (ClutterActor           *self,
2380                                          const ClutterActorBox  *box,
2381                                          ClutterAllocationFlags  flags);
2382
2383 static inline void
2384 clutter_actor_maybe_layout_children (ClutterActor           *self,
2385                                      const ClutterActorBox  *allocation,
2386                                      ClutterAllocationFlags  flags)
2387 {
2388   ClutterActorPrivate *priv = self->priv;
2389
2390   /* this is going to be a bit hard to follow, so let's put an explanation
2391    * here.
2392    *
2393    * we want ClutterActor to have a default layout manager if the actor was
2394    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2395    *
2396    * we also want any subclass of ClutterActor that does not override the
2397    * ::allocate() virtual function to delegate to a layout manager.
2398    *
2399    * finally, we want to allow people subclassing ClutterActor and overriding
2400    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2401    *
2402    * on the other hand, we want existing actor subclasses overriding the
2403    * ::allocate() virtual function and chaining up to the parent's
2404    * implementation to continue working without allocating their children
2405    * twice, or without entering an allocation loop.
2406    *
2407    * for the first two points, we check if the class of the actor is
2408    * overridding the ::allocate() virtual function; if it isn't, then we
2409    * follow through with checking whether we have children and a layout
2410    * manager, and eventually calling clutter_layout_manager_allocate().
2411    *
2412    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2413    * allocation flags that we got passed, and if it is present, we continue
2414    * with the check above.
2415    *
2416    * if neither of these two checks yields a positive result, we just
2417    * assume that the ::allocate() virtual function that resulted in this
2418    * function being called will also allocate the children of the actor.
2419    */
2420
2421   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2422     goto check_layout;
2423
2424   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2425     goto check_layout;
2426
2427   return;
2428
2429 check_layout:
2430   if (priv->n_children != 0 &&
2431       priv->layout_manager != NULL)
2432     {
2433       ClutterContainer *container = CLUTTER_CONTAINER (self);
2434       ClutterAllocationFlags children_flags;
2435       ClutterActorBox children_box;
2436
2437       /* normalize the box passed to the layout manager */
2438       children_box.x1 = children_box.y1 = 0.f;
2439       children_box.x2 = (allocation->x2 - allocation->x1);
2440       children_box.y2 = (allocation->y2 - allocation->y1);
2441
2442       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2443        * the actor's children, since it refers only to the current
2444        * actor's allocation.
2445        */
2446       children_flags = flags;
2447       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2448
2449       CLUTTER_NOTE (LAYOUT,
2450                     "Allocating %d children of %s "
2451                     "at { %.2f, %.2f - %.2f x %.2f } "
2452                     "using %s",
2453                     priv->n_children,
2454                     _clutter_actor_get_debug_name (self),
2455                     allocation->x1,
2456                     allocation->y1,
2457                     (allocation->x2 - allocation->x1),
2458                     (allocation->y2 - allocation->y1),
2459                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2460
2461       clutter_layout_manager_allocate (priv->layout_manager,
2462                                        container,
2463                                        &children_box,
2464                                        children_flags);
2465     }
2466 }
2467
2468 static void
2469 clutter_actor_real_allocate (ClutterActor           *self,
2470                              const ClutterActorBox  *box,
2471                              ClutterAllocationFlags  flags)
2472 {
2473   ClutterActorPrivate *priv = self->priv;
2474   gboolean changed;
2475
2476   g_object_freeze_notify (G_OBJECT (self));
2477
2478   changed = clutter_actor_set_allocation_internal (self, box, flags);
2479
2480   /* we allocate our children before we notify changes in our geometry,
2481    * so that people connecting to properties will be able to get valid
2482    * data out of the sub-tree of the scene graph that has this actor at
2483    * the root.
2484    */
2485   clutter_actor_maybe_layout_children (self, box, flags);
2486
2487   if (changed)
2488     {
2489       ClutterActorBox signal_box = priv->allocation;
2490       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2491
2492       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2493                      &signal_box,
2494                      signal_flags);
2495     }
2496
2497   g_object_thaw_notify (G_OBJECT (self));
2498 }
2499
2500 static void
2501 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2502                                     ClutterActor *origin)
2503 {
2504   /* no point in queuing a redraw on a destroyed actor */
2505   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2506     return;
2507
2508   /* NB: We can't bail out early here if the actor is hidden in case
2509    * the actor bas been cloned. In this case the clone will need to
2510    * receive the signal so it can queue its own redraw.
2511    */
2512
2513   /* calls klass->queue_redraw in default handler */
2514   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2515 }
2516
2517 static void
2518 clutter_actor_real_queue_redraw (ClutterActor *self,
2519                                  ClutterActor *origin)
2520 {
2521   ClutterActor *parent;
2522
2523   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2524                 _clutter_actor_get_debug_name (self),
2525                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2526                                : "same actor");
2527
2528   /* no point in queuing a redraw on a destroyed actor */
2529   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2530     return;
2531
2532   /* If the queue redraw is coming from a child then the actor has
2533      become dirty and any queued effect is no longer valid */
2534   if (self != origin)
2535     {
2536       self->priv->is_dirty = TRUE;
2537       self->priv->effect_to_redraw = NULL;
2538     }
2539
2540   /* If the actor isn't visible, we still had to emit the signal
2541    * to allow for a ClutterClone, but the appearance of the parent
2542    * won't change so we don't have to propagate up the hierarchy.
2543    */
2544   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2545     return;
2546
2547   /* Although we could determine here that a full stage redraw
2548    * has already been queued and immediately bail out, we actually
2549    * guarantee that we will propagate a queue-redraw signal to our
2550    * parent at least once so that it's possible to implement a
2551    * container that tracks which of its children have queued a
2552    * redraw.
2553    */
2554   if (self->priv->propagated_one_redraw)
2555     {
2556       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2557       if (stage != NULL &&
2558           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2559         return;
2560     }
2561
2562   self->priv->propagated_one_redraw = TRUE;
2563
2564   /* notify parents, if they are all visible eventually we'll
2565    * queue redraw on the stage, which queues the redraw idle.
2566    */
2567   parent = clutter_actor_get_parent (self);
2568   if (parent != NULL)
2569     {
2570       /* this will go up recursively */
2571       _clutter_actor_signal_queue_redraw (parent, origin);
2572     }
2573 }
2574
2575 static void
2576 clutter_actor_real_queue_relayout (ClutterActor *self)
2577 {
2578   ClutterActorPrivate *priv = self->priv;
2579
2580   /* no point in queueing a redraw on a destroyed actor */
2581   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2582     return;
2583
2584   priv->needs_width_request  = TRUE;
2585   priv->needs_height_request = TRUE;
2586   priv->needs_allocation     = TRUE;
2587
2588   /* reset the cached size requests */
2589   memset (priv->width_requests, 0,
2590           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2591   memset (priv->height_requests, 0,
2592           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2593
2594   /* We need to go all the way up the hierarchy */
2595   if (priv->parent != NULL)
2596     _clutter_actor_queue_only_relayout (priv->parent);
2597 }
2598
2599 /**
2600  * clutter_actor_apply_relative_transform_to_point:
2601  * @self: A #ClutterActor
2602  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2603  *   default #ClutterStage
2604  * @point: A point as #ClutterVertex
2605  * @vertex: (out caller-allocates): The translated #ClutterVertex
2606  *
2607  * Transforms @point in coordinates relative to the actor into
2608  * ancestor-relative coordinates using the relevant transform
2609  * stack (i.e. scale, rotation, etc).
2610  *
2611  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2612  * this case, the coordinates returned will be the coordinates on
2613  * the stage before the projection is applied. This is different from
2614  * the behaviour of clutter_actor_apply_transform_to_point().
2615  *
2616  * Since: 0.6
2617  */
2618 void
2619 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2620                                                  ClutterActor        *ancestor,
2621                                                  const ClutterVertex *point,
2622                                                  ClutterVertex       *vertex)
2623 {
2624   gfloat w;
2625   CoglMatrix matrix;
2626
2627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2628   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2629   g_return_if_fail (point != NULL);
2630   g_return_if_fail (vertex != NULL);
2631
2632   *vertex = *point;
2633   w = 1.0;
2634
2635   if (ancestor == NULL)
2636     ancestor = _clutter_actor_get_stage_internal (self);
2637
2638   if (ancestor == NULL)
2639     {
2640       *vertex = *point;
2641       return;
2642     }
2643
2644   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2645   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2646 }
2647
2648 static gboolean
2649 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2650                                          const ClutterVertex *vertices_in,
2651                                          ClutterVertex *vertices_out,
2652                                          int n_vertices)
2653 {
2654   ClutterActor *stage;
2655   CoglMatrix modelview;
2656   CoglMatrix projection;
2657   float viewport[4];
2658
2659   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2660
2661   stage = _clutter_actor_get_stage_internal (self);
2662
2663   /* We really can't do anything meaningful in this case so don't try
2664    * to do any transform */
2665   if (stage == NULL)
2666     return FALSE;
2667
2668   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2669    * that gets us to stage coordinates, we want to go all the way to eye
2670    * coordinates */
2671   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2672
2673   /* Fetch the projection and viewport */
2674   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2675   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2676                                &viewport[0],
2677                                &viewport[1],
2678                                &viewport[2],
2679                                &viewport[3]);
2680
2681   _clutter_util_fully_transform_vertices (&modelview,
2682                                           &projection,
2683                                           viewport,
2684                                           vertices_in,
2685                                           vertices_out,
2686                                           n_vertices);
2687
2688   return TRUE;
2689 }
2690
2691 /**
2692  * clutter_actor_apply_transform_to_point:
2693  * @self: A #ClutterActor
2694  * @point: A point as #ClutterVertex
2695  * @vertex: (out caller-allocates): The translated #ClutterVertex
2696  *
2697  * Transforms @point in coordinates relative to the actor
2698  * into screen-relative coordinates with the current actor
2699  * transformation (i.e. scale, rotation, etc)
2700  *
2701  * Since: 0.4
2702  **/
2703 void
2704 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2705                                         const ClutterVertex *point,
2706                                         ClutterVertex       *vertex)
2707 {
2708   g_return_if_fail (point != NULL);
2709   g_return_if_fail (vertex != NULL);
2710   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2711 }
2712
2713 /*
2714  * _clutter_actor_get_relative_transformation_matrix:
2715  * @self: The actor whose coordinate space you want to transform from.
2716  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2717  *            or %NULL if you want to transform all the way to eye coordinates.
2718  * @matrix: A #CoglMatrix to store the transformation
2719  *
2720  * This gets a transformation @matrix that will transform coordinates from the
2721  * coordinate space of @self into the coordinate space of @ancestor.
2722  *
2723  * For example if you need a matrix that can transform the local actor
2724  * coordinates of @self into stage coordinates you would pass the actor's stage
2725  * pointer as the @ancestor.
2726  *
2727  * If you pass %NULL then the transformation will take you all the way through
2728  * to eye coordinates. This can be useful if you want to extract the entire
2729  * modelview transform that Clutter applies before applying the projection
2730  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2731  * using cogl_set_modelview_matrix() for example then you would want a matrix
2732  * that transforms into eye coordinates.
2733  *
2734  * <note><para>This function explicitly initializes the given @matrix. If you just
2735  * want clutter to multiply a relative transformation with an existing matrix
2736  * you can use clutter_actor_apply_relative_transformation_matrix()
2737  * instead.</para></note>
2738  *
2739  */
2740 /* XXX: We should consider caching the stage relative modelview along with
2741  * the actor itself */
2742 static void
2743 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2744                                                    ClutterActor *ancestor,
2745                                                    CoglMatrix *matrix)
2746 {
2747   cogl_matrix_init_identity (matrix);
2748
2749   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2750 }
2751
2752 /* Project the given @box into stage window coordinates, writing the
2753  * transformed vertices to @verts[]. */
2754 static gboolean
2755 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2756                                           const ClutterActorBox *box,
2757                                           ClutterVertex          verts[])
2758 {
2759   ClutterVertex box_vertices[4];
2760
2761   box_vertices[0].x = box->x1;
2762   box_vertices[0].y = box->y1;
2763   box_vertices[0].z = 0;
2764   box_vertices[1].x = box->x2;
2765   box_vertices[1].y = box->y1;
2766   box_vertices[1].z = 0;
2767   box_vertices[2].x = box->x1;
2768   box_vertices[2].y = box->y2;
2769   box_vertices[2].z = 0;
2770   box_vertices[3].x = box->x2;
2771   box_vertices[3].y = box->y2;
2772   box_vertices[3].z = 0;
2773
2774   return
2775     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2776 }
2777
2778 /**
2779  * clutter_actor_get_allocation_vertices:
2780  * @self: A #ClutterActor
2781  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2782  *   against, or %NULL to use the #ClutterStage
2783  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2784  *   location for an array of 4 #ClutterVertex in which to store the result
2785  *
2786  * Calculates the transformed coordinates of the four corners of the
2787  * actor in the plane of @ancestor. The returned vertices relate to
2788  * the #ClutterActorBox coordinates as follows:
2789  * <itemizedlist>
2790  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2791  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2792  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2793  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2794  * </itemizedlist>
2795  *
2796  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2797  * this case, the coordinates returned will be the coordinates on
2798  * the stage before the projection is applied. This is different from
2799  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2800  *
2801  * Since: 0.6
2802  */
2803 void
2804 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2805                                        ClutterActor  *ancestor,
2806                                        ClutterVertex  verts[])
2807 {
2808   ClutterActorPrivate *priv;
2809   ClutterActorBox box;
2810   ClutterVertex vertices[4];
2811   CoglMatrix modelview;
2812
2813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2814   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2815
2816   if (ancestor == NULL)
2817     ancestor = _clutter_actor_get_stage_internal (self);
2818
2819   /* Fallback to a NOP transform if the actor isn't parented under a
2820    * stage. */
2821   if (ancestor == NULL)
2822     ancestor = self;
2823
2824   priv = self->priv;
2825
2826   /* if the actor needs to be allocated we force a relayout, so that
2827    * we will have valid values to use in the transformations */
2828   if (priv->needs_allocation)
2829     {
2830       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2831       if (stage)
2832         _clutter_stage_maybe_relayout (stage);
2833       else
2834         {
2835           box.x1 = box.y1 = 0;
2836           /* The result isn't really meaningful in this case but at
2837            * least try to do something *vaguely* reasonable... */
2838           clutter_actor_get_size (self, &box.x2, &box.y2);
2839         }
2840     }
2841
2842   clutter_actor_get_allocation_box (self, &box);
2843
2844   vertices[0].x = box.x1;
2845   vertices[0].y = box.y1;
2846   vertices[0].z = 0;
2847   vertices[1].x = box.x2;
2848   vertices[1].y = box.y1;
2849   vertices[1].z = 0;
2850   vertices[2].x = box.x1;
2851   vertices[2].y = box.y2;
2852   vertices[2].z = 0;
2853   vertices[3].x = box.x2;
2854   vertices[3].y = box.y2;
2855   vertices[3].z = 0;
2856
2857   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2858                                                      &modelview);
2859
2860   cogl_matrix_transform_points (&modelview,
2861                                 3,
2862                                 sizeof (ClutterVertex),
2863                                 vertices,
2864                                 sizeof (ClutterVertex),
2865                                 vertices,
2866                                 4);
2867 }
2868
2869 /**
2870  * clutter_actor_get_abs_allocation_vertices:
2871  * @self: A #ClutterActor
2872  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2873  *   of 4 #ClutterVertex where to store the result.
2874  *
2875  * Calculates the transformed screen coordinates of the four corners of
2876  * the actor; the returned vertices relate to the #ClutterActorBox
2877  * coordinates  as follows:
2878  * <itemizedlist>
2879  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2880  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2881  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2882  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2883  * </itemizedlist>
2884  *
2885  * Since: 0.4
2886  */
2887 void
2888 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2889                                            ClutterVertex  verts[])
2890 {
2891   ClutterActorPrivate *priv;
2892   ClutterActorBox actor_space_allocation;
2893
2894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2895
2896   priv = self->priv;
2897
2898   /* if the actor needs to be allocated we force a relayout, so that
2899    * the actor allocation box will be valid for
2900    * _clutter_actor_transform_and_project_box()
2901    */
2902   if (priv->needs_allocation)
2903     {
2904       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2905       /* There's nothing meaningful we can do now */
2906       if (!stage)
2907         return;
2908
2909       _clutter_stage_maybe_relayout (stage);
2910     }
2911
2912   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2913    * own coordinate space... */
2914   actor_space_allocation.x1 = 0;
2915   actor_space_allocation.y1 = 0;
2916   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2917   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2918   _clutter_actor_transform_and_project_box (self,
2919                                             &actor_space_allocation,
2920                                             verts);
2921 }
2922
2923 static void
2924 clutter_actor_real_apply_transform (ClutterActor *self,
2925                                     CoglMatrix   *matrix)
2926 {
2927   ClutterActorPrivate *priv = self->priv;
2928
2929   if (!priv->transform_valid)
2930     {
2931       CoglMatrix *transform = &priv->transform;
2932       const ClutterTransformInfo *info;
2933
2934       info = _clutter_actor_get_transform_info_or_defaults (self);
2935
2936       cogl_matrix_init_identity (transform);
2937
2938       cogl_matrix_translate (transform,
2939                              priv->allocation.x1,
2940                              priv->allocation.y1,
2941                              0.0);
2942
2943       if (info->depth)
2944         cogl_matrix_translate (transform, 0, 0, info->depth);
2945
2946       /*
2947        * because the rotation involves translations, we must scale
2948        * before applying the rotations (if we apply the scale after
2949        * the rotations, the translations included in the rotation are
2950        * not scaled and so the entire object will move on the screen
2951        * as a result of rotating it).
2952        */
2953       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2954         {
2955           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2956                                         &info->scale_center,
2957                                         cogl_matrix_scale (transform,
2958                                                            info->scale_x,
2959                                                            info->scale_y,
2960                                                            1.0));
2961         }
2962
2963       if (info->rz_angle)
2964         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2965                                       &info->rz_center,
2966                                       cogl_matrix_rotate (transform,
2967                                                           info->rz_angle,
2968                                                           0, 0, 1.0));
2969
2970       if (info->ry_angle)
2971         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2972                                       &info->ry_center,
2973                                       cogl_matrix_rotate (transform,
2974                                                           info->ry_angle,
2975                                                           0, 1.0, 0));
2976
2977       if (info->rx_angle)
2978         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2979                                       &info->rx_center,
2980                                       cogl_matrix_rotate (transform,
2981                                                           info->rx_angle,
2982                                                           1.0, 0, 0));
2983
2984       if (!clutter_anchor_coord_is_zero (&info->anchor))
2985         {
2986           gfloat x, y, z;
2987
2988           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2989           cogl_matrix_translate (transform, -x, -y, -z);
2990         }
2991
2992       priv->transform_valid = TRUE;
2993     }
2994
2995   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2996 }
2997
2998 /* Applies the transforms associated with this actor to the given
2999  * matrix. */
3000 void
3001 _clutter_actor_apply_modelview_transform (ClutterActor *self,
3002                                           CoglMatrix *matrix)
3003 {
3004   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
3005 }
3006
3007 /*
3008  * clutter_actor_apply_relative_transformation_matrix:
3009  * @self: The actor whose coordinate space you want to transform from.
3010  * @ancestor: The ancestor actor whose coordinate space you want to transform too
3011  *            or %NULL if you want to transform all the way to eye coordinates.
3012  * @matrix: A #CoglMatrix to apply the transformation too.
3013  *
3014  * This multiplies a transform with @matrix that will transform coordinates
3015  * from the coordinate space of @self into the coordinate space of @ancestor.
3016  *
3017  * For example if you need a matrix that can transform the local actor
3018  * coordinates of @self into stage coordinates you would pass the actor's stage
3019  * pointer as the @ancestor.
3020  *
3021  * If you pass %NULL then the transformation will take you all the way through
3022  * to eye coordinates. This can be useful if you want to extract the entire
3023  * modelview transform that Clutter applies before applying the projection
3024  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
3025  * using cogl_set_modelview_matrix() for example then you would want a matrix
3026  * that transforms into eye coordinates.
3027  *
3028  * <note>This function doesn't initialize the given @matrix, it simply
3029  * multiplies the requested transformation matrix with the existing contents of
3030  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3031  * before calling this function, or you can use
3032  * clutter_actor_get_relative_transformation_matrix() instead.</note>
3033  */
3034 void
3035 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3036                                                      ClutterActor *ancestor,
3037                                                      CoglMatrix *matrix)
3038 {
3039   ClutterActor *parent;
3040
3041   /* Note we terminate before ever calling stage->apply_transform()
3042    * since that would conceptually be relative to the underlying
3043    * window OpenGL coordinates so we'd need a special @ancestor
3044    * value to represent the fake parent of the stage. */
3045   if (self == ancestor)
3046     return;
3047
3048   parent = clutter_actor_get_parent (self);
3049
3050   if (parent != NULL)
3051     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3052                                                          matrix);
3053
3054   _clutter_actor_apply_modelview_transform (self, matrix);
3055 }
3056
3057 static void
3058 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3059                                        ClutterPaintVolume *pv,
3060                                        const char *label,
3061                                        const CoglColor *color)
3062 {
3063   static CoglPipeline *outline = NULL;
3064   CoglPrimitive *prim;
3065   ClutterVertex line_ends[12 * 2];
3066   int n_vertices;
3067   CoglContext *ctx =
3068     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3069   /* XXX: at some point we'll query this from the stage but we can't
3070    * do that until the osx backend uses Cogl natively. */
3071   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3072
3073   if (outline == NULL)
3074     outline = cogl_pipeline_new (ctx);
3075
3076   _clutter_paint_volume_complete (pv);
3077
3078   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3079
3080   /* Front face */
3081   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3082   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3083   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3084   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3085
3086   if (!pv->is_2d)
3087     {
3088       /* Back face */
3089       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3090       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3091       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3092       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3093
3094       /* Lines connecting front face to back face */
3095       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3096       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3097       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3098       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3099     }
3100
3101   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3102                                 n_vertices,
3103                                 (CoglVertexP3 *)line_ends);
3104
3105   cogl_pipeline_set_color (outline, color);
3106   cogl_framebuffer_draw_primitive (fb, outline, prim);
3107   cogl_object_unref (prim);
3108
3109   if (label)
3110     {
3111       PangoLayout *layout;
3112       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3113       pango_layout_set_text (layout, label, -1);
3114       cogl_pango_render_layout (layout,
3115                                 pv->vertices[0].x,
3116                                 pv->vertices[0].y,
3117                                 color,
3118                                 0);
3119       g_object_unref (layout);
3120     }
3121 }
3122
3123 static void
3124 _clutter_actor_draw_paint_volume (ClutterActor *self)
3125 {
3126   ClutterPaintVolume *pv;
3127   CoglColor color;
3128
3129   pv = _clutter_actor_get_paint_volume_mutable (self);
3130   if (!pv)
3131     {
3132       gfloat width, height;
3133       ClutterPaintVolume fake_pv;
3134
3135       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3136       _clutter_paint_volume_init_static (&fake_pv, stage);
3137
3138       clutter_actor_get_size (self, &width, &height);
3139       clutter_paint_volume_set_width (&fake_pv, width);
3140       clutter_paint_volume_set_height (&fake_pv, height);
3141
3142       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3143       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3144                                              _clutter_actor_get_debug_name (self),
3145                                              &color);
3146
3147       clutter_paint_volume_free (&fake_pv);
3148     }
3149   else
3150     {
3151       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3152       _clutter_actor_draw_paint_volume_full (self, pv,
3153                                              _clutter_actor_get_debug_name (self),
3154                                              &color);
3155     }
3156 }
3157
3158 static void
3159 _clutter_actor_paint_cull_result (ClutterActor *self,
3160                                   gboolean success,
3161                                   ClutterCullResult result)
3162 {
3163   ClutterPaintVolume *pv;
3164   CoglColor color;
3165
3166   if (success)
3167     {
3168       if (result == CLUTTER_CULL_RESULT_IN)
3169         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3170       else if (result == CLUTTER_CULL_RESULT_OUT)
3171         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3172       else
3173         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3174     }
3175   else
3176     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3177
3178   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3179     _clutter_actor_draw_paint_volume_full (self, pv,
3180                                            _clutter_actor_get_debug_name (self),
3181                                            &color);
3182   else
3183     {
3184       PangoLayout *layout;
3185       char *label =
3186         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3187       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3188       cogl_set_source_color (&color);
3189
3190       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3191       pango_layout_set_text (layout, label, -1);
3192       cogl_pango_render_layout (layout,
3193                                 0,
3194                                 0,
3195                                 &color,
3196                                 0);
3197       g_free (label);
3198       g_object_unref (layout);
3199     }
3200 }
3201
3202 static int clone_paint_level = 0;
3203
3204 void
3205 _clutter_actor_push_clone_paint (void)
3206 {
3207   clone_paint_level++;
3208 }
3209
3210 void
3211 _clutter_actor_pop_clone_paint (void)
3212 {
3213   clone_paint_level--;
3214 }
3215
3216 static gboolean
3217 in_clone_paint (void)
3218 {
3219   return clone_paint_level > 0;
3220 }
3221
3222 /* Returns TRUE if the actor can be ignored */
3223 /* FIXME: we should return a ClutterCullResult, and
3224  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3225  * means there's no point in trying to cull descendants of the current
3226  * node. */
3227 static gboolean
3228 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3229 {
3230   ClutterActorPrivate *priv = self->priv;
3231   ClutterActor *stage;
3232   const ClutterPlane *stage_clip;
3233
3234   if (!priv->last_paint_volume_valid)
3235     {
3236       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3237                     "->last_paint_volume_valid == FALSE",
3238                     _clutter_actor_get_debug_name (self));
3239       return FALSE;
3240     }
3241
3242   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3243     return FALSE;
3244
3245   stage = _clutter_actor_get_stage_internal (self);
3246   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3247   if (G_UNLIKELY (!stage_clip))
3248     {
3249       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3250                     "No stage clip set",
3251                     _clutter_actor_get_debug_name (self));
3252       return FALSE;
3253     }
3254
3255   if (cogl_get_draw_framebuffer () !=
3256       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3257     {
3258       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3259                     "Current framebuffer doesn't correspond to stage",
3260                     _clutter_actor_get_debug_name (self));
3261       return FALSE;
3262     }
3263
3264   *result_out =
3265     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3266   return TRUE;
3267 }
3268
3269 static void
3270 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3271 {
3272   ClutterActorPrivate *priv = self->priv;
3273   const ClutterPaintVolume *pv;
3274
3275   if (priv->last_paint_volume_valid)
3276     {
3277       clutter_paint_volume_free (&priv->last_paint_volume);
3278       priv->last_paint_volume_valid = FALSE;
3279     }
3280
3281   pv = clutter_actor_get_paint_volume (self);
3282   if (!pv)
3283     {
3284       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3285                     "Actor failed to report a paint volume",
3286                     _clutter_actor_get_debug_name (self));
3287       return;
3288     }
3289
3290   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3291
3292   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3293                                             NULL); /* eye coordinates */
3294
3295   priv->last_paint_volume_valid = TRUE;
3296 }
3297
3298 static inline gboolean
3299 actor_has_shader_data (ClutterActor *self)
3300 {
3301   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3302 }
3303
3304 guint32
3305 _clutter_actor_get_pick_id (ClutterActor *self)
3306 {
3307   if (self->priv->pick_id < 0)
3308     return 0;
3309
3310   return self->priv->pick_id;
3311 }
3312
3313 /* This is the same as clutter_actor_add_effect except that it doesn't
3314    queue a redraw and it doesn't notify on the effect property */
3315 static void
3316 _clutter_actor_add_effect_internal (ClutterActor  *self,
3317                                     ClutterEffect *effect)
3318 {
3319   ClutterActorPrivate *priv = self->priv;
3320
3321   if (priv->effects == NULL)
3322     {
3323       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3324       priv->effects->actor = self;
3325     }
3326
3327   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3328 }
3329
3330 /* This is the same as clutter_actor_remove_effect except that it doesn't
3331    queue a redraw and it doesn't notify on the effect property */
3332 static void
3333 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3334                                        ClutterEffect *effect)
3335 {
3336   ClutterActorPrivate *priv = self->priv;
3337
3338   if (priv->effects == NULL)
3339     return;
3340
3341   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3342
3343   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3344     g_clear_object (&priv->effects);
3345 }
3346
3347 static gboolean
3348 needs_flatten_effect (ClutterActor *self)
3349 {
3350   ClutterActorPrivate *priv = self->priv;
3351
3352   if (G_UNLIKELY (clutter_paint_debug_flags &
3353                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3354     return FALSE;
3355
3356   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3357     return TRUE;
3358   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3359     {
3360       if (clutter_actor_get_paint_opacity (self) < 255 &&
3361           clutter_actor_has_overlaps (self))
3362         return TRUE;
3363     }
3364
3365   return FALSE;
3366 }
3367
3368 static void
3369 add_or_remove_flatten_effect (ClutterActor *self)
3370 {
3371   ClutterActorPrivate *priv = self->priv;
3372
3373   /* Add or remove the flatten effect depending on the
3374      offscreen-redirect property. */
3375   if (needs_flatten_effect (self))
3376     {
3377       if (priv->flatten_effect == NULL)
3378         {
3379           ClutterActorMeta *actor_meta;
3380           gint priority;
3381
3382           priv->flatten_effect = _clutter_flatten_effect_new ();
3383           /* Keep a reference to the effect so that we can queue
3384              redraws from it */
3385           g_object_ref_sink (priv->flatten_effect);
3386
3387           /* Set the priority of the effect to high so that it will
3388              always be applied to the actor first. It uses an internal
3389              priority so that it won't be visible to applications */
3390           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3391           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3392           _clutter_actor_meta_set_priority (actor_meta, priority);
3393
3394           /* This will add the effect without queueing a redraw */
3395           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3396         }
3397     }
3398   else
3399     {
3400       if (priv->flatten_effect != NULL)
3401         {
3402           /* Destroy the effect so that it will lose its fbo cache of
3403              the actor */
3404           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3405           g_clear_object (&priv->flatten_effect);
3406         }
3407     }
3408 }
3409
3410 static void
3411 clutter_actor_real_paint (ClutterActor *actor)
3412 {
3413   ClutterActorPrivate *priv = actor->priv;
3414   ClutterActor *iter;
3415
3416   for (iter = priv->first_child;
3417        iter != NULL;
3418        iter = iter->priv->next_sibling)
3419     {
3420       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3421                     _clutter_actor_get_debug_name (iter),
3422                     _clutter_actor_get_debug_name (actor),
3423                     iter->priv->allocation.x1,
3424                     iter->priv->allocation.y1,
3425                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3426                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3427
3428       clutter_actor_paint (iter);
3429     }
3430 }
3431
3432 static gboolean
3433 clutter_actor_paint_node (ClutterActor     *actor,
3434                           ClutterPaintNode *root)
3435 {
3436   ClutterActorPrivate *priv = actor->priv;
3437
3438   if (root == NULL)
3439     return FALSE;
3440
3441   if (priv->bg_color_set &&
3442       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3443     {
3444       ClutterPaintNode *node;
3445       ClutterColor bg_color;
3446       ClutterActorBox box;
3447
3448       box.x1 = 0.f;
3449       box.y1 = 0.f;
3450       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3451       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3452
3453       bg_color = priv->bg_color;
3454       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3455                      * priv->bg_color.alpha
3456                      / 255;
3457
3458       node = clutter_color_node_new (&bg_color);
3459       clutter_paint_node_set_name (node, "backgroundColor");
3460       clutter_paint_node_add_rectangle (node, &box);
3461       clutter_paint_node_add_child (root, node);
3462       clutter_paint_node_unref (node);
3463     }
3464
3465   if (priv->content != NULL)
3466     _clutter_content_paint_content (priv->content, actor, root);
3467
3468   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3469     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3470
3471   if (clutter_paint_node_get_n_children (root) == 0)
3472     return FALSE;
3473
3474 #ifdef CLUTTER_ENABLE_DEBUG
3475   if (CLUTTER_HAS_DEBUG (PAINT))
3476     {
3477       /* dump the tree only if we have one */
3478       _clutter_paint_node_dump_tree (root);
3479     }
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3481
3482   _clutter_paint_node_paint (root);
3483
3484 #if 0
3485   /* XXX: Uncomment this when we disable emitting the paint signal */
3486   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3487 #endif
3488
3489   return TRUE;
3490 }
3491
3492 /**
3493  * clutter_actor_paint:
3494  * @self: A #ClutterActor
3495  *
3496  * Renders the actor to display.
3497  *
3498  * This function should not be called directly by applications.
3499  * Call clutter_actor_queue_redraw() to queue paints, instead.
3500  *
3501  * This function is context-aware, and will either cause a
3502  * regular paint or a pick paint.
3503  *
3504  * This function will emit the #ClutterActor::paint signal or
3505  * the #ClutterActor::pick signal, depending on the context.
3506  *
3507  * This function does not paint the actor if the actor is set to 0,
3508  * unless it is performing a pick paint.
3509  */
3510 void
3511 clutter_actor_paint (ClutterActor *self)
3512 {
3513   ClutterActorPrivate *priv;
3514   ClutterPickMode pick_mode;
3515   gboolean clip_set = FALSE;
3516   gboolean shader_applied = FALSE;
3517
3518   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3519                           "Actor real-paint counter",
3520                           "Increments each time any actor is painted",
3521                           0 /* no application private data */);
3522   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3523                           "Actor pick-paint counter",
3524                           "Increments each time any actor is painted "
3525                           "for picking",
3526                           0 /* no application private data */);
3527
3528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3529
3530   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3531     return;
3532
3533   priv = self->priv;
3534
3535   pick_mode = _clutter_context_get_pick_mode ();
3536
3537   if (pick_mode == CLUTTER_PICK_NONE)
3538     priv->propagated_one_redraw = FALSE;
3539
3540   /* It's an important optimization that we consider painting of
3541    * actors with 0 opacity to be a NOP... */
3542   if (pick_mode == CLUTTER_PICK_NONE &&
3543       /* ignore top-levels, since they might be transparent */
3544       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3545       /* Use the override opacity if its been set */
3546       ((priv->opacity_override >= 0) ?
3547        priv->opacity_override : priv->opacity) == 0)
3548     return;
3549
3550   /* if we aren't paintable (not in a toplevel with all
3551    * parents paintable) then do nothing.
3552    */
3553   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3554     return;
3555
3556   /* mark that we are in the paint process */
3557   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3558
3559   cogl_push_matrix();
3560
3561   if (priv->enable_model_view_transform)
3562     {
3563       CoglMatrix matrix;
3564
3565       /* XXX: It could be better to cache the modelview with the actor
3566        * instead of progressively building up the transformations on
3567        * the matrix stack every time we paint. */
3568       cogl_get_modelview_matrix (&matrix);
3569       _clutter_actor_apply_modelview_transform (self, &matrix);
3570
3571 #ifdef CLUTTER_ENABLE_DEBUG
3572       /* Catch when out-of-band transforms have been made by actors not as part
3573        * of an apply_transform vfunc... */
3574       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3575         {
3576           CoglMatrix expected_matrix;
3577
3578           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3579                                                              &expected_matrix);
3580
3581           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3582             {
3583               GString *buf = g_string_sized_new (1024);
3584               ClutterActor *parent;
3585
3586               parent = self;
3587               while (parent != NULL)
3588                 {
3589                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3590
3591                   if (parent->priv->parent != NULL)
3592                     g_string_append (buf, "->");
3593
3594                   parent = parent->priv->parent;
3595                 }
3596
3597               g_warning ("Unexpected transform found when painting actor "
3598                          "\"%s\". This will be caused by one of the actor's "
3599                          "ancestors (%s) using the Cogl API directly to transform "
3600                          "children instead of using ::apply_transform().",
3601                          _clutter_actor_get_debug_name (self),
3602                          buf->str);
3603
3604               g_string_free (buf, TRUE);
3605             }
3606         }
3607 #endif /* CLUTTER_ENABLE_DEBUG */
3608
3609       cogl_set_modelview_matrix (&matrix);
3610     }
3611
3612   if (priv->has_clip)
3613     {
3614       cogl_clip_push_rectangle (priv->clip.x,
3615                                 priv->clip.y,
3616                                 priv->clip.x + priv->clip.width,
3617                                 priv->clip.y + priv->clip.height);
3618       clip_set = TRUE;
3619     }
3620   else if (priv->clip_to_allocation)
3621     {
3622       gfloat width, height;
3623
3624       width  = priv->allocation.x2 - priv->allocation.x1;
3625       height = priv->allocation.y2 - priv->allocation.y1;
3626
3627       cogl_clip_push_rectangle (0, 0, width, height);
3628       clip_set = TRUE;
3629     }
3630
3631   if (pick_mode == CLUTTER_PICK_NONE)
3632     {
3633       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3634
3635       /* We check whether we need to add the flatten effect before
3636          each paint so that we can avoid having a mechanism for
3637          applications to notify when the value of the
3638          has_overlaps virtual changes. */
3639       add_or_remove_flatten_effect (self);
3640     }
3641   else
3642     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3643
3644   /* We save the current paint volume so that the next time the
3645    * actor queues a redraw we can constrain the redraw to just
3646    * cover the union of the new bounding box and the old.
3647    *
3648    * We also fetch the current paint volume to perform culling so
3649    * we can avoid painting actors outside the current clip region.
3650    *
3651    * If we are painting inside a clone, we should neither update
3652    * the paint volume or use it to cull painting, since the paint
3653    * box represents the location of the source actor on the
3654    * screen.
3655    *
3656    * XXX: We are starting to do a lot of vertex transforms on
3657    * the CPU in a typical paint, so at some point we should
3658    * audit these and consider caching some things.
3659    *
3660    * NB: We don't perform culling while picking at this point because
3661    * clutter-stage.c doesn't setup the clipping planes appropriately.
3662    *
3663    * NB: We don't want to update the last-paint-volume during picking
3664    * because the last-paint-volume is used to determine the old screen
3665    * space location of an actor that has moved so we can know the
3666    * minimal region to redraw to clear an old view of the actor. If we
3667    * update this during picking then by the time we come around to
3668    * paint then the last-paint-volume would likely represent the new
3669    * actor position not the old.
3670    */
3671   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3672     {
3673       gboolean success;
3674       /* annoyingly gcc warns if uninitialized even though
3675        * the initialization is redundant :-( */
3676       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3677
3678       if (G_LIKELY ((clutter_paint_debug_flags &
3679                      (CLUTTER_DEBUG_DISABLE_CULLING |
3680                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3681                     (CLUTTER_DEBUG_DISABLE_CULLING |
3682                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3683         _clutter_actor_update_last_paint_volume (self);
3684
3685       success = cull_actor (self, &result);
3686
3687       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3688         _clutter_actor_paint_cull_result (self, success, result);
3689       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3690         goto done;
3691     }
3692
3693   if (priv->effects == NULL)
3694     {
3695       if (pick_mode == CLUTTER_PICK_NONE &&
3696           actor_has_shader_data (self))
3697         {
3698           _clutter_actor_shader_pre_paint (self, FALSE);
3699           shader_applied = TRUE;
3700         }
3701
3702       priv->next_effect_to_paint = NULL;
3703     }
3704   else
3705     priv->next_effect_to_paint =
3706       _clutter_meta_group_peek_metas (priv->effects);
3707
3708   clutter_actor_continue_paint (self);
3709
3710   if (shader_applied)
3711     _clutter_actor_shader_post_paint (self);
3712
3713   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3714                   pick_mode == CLUTTER_PICK_NONE))
3715     _clutter_actor_draw_paint_volume (self);
3716
3717 done:
3718   /* If we make it here then the actor has run through a complete
3719      paint run including all the effects so it's no longer dirty */
3720   if (pick_mode == CLUTTER_PICK_NONE)
3721     priv->is_dirty = FALSE;
3722
3723   if (clip_set)
3724     cogl_clip_pop();
3725
3726   cogl_pop_matrix();
3727
3728   /* paint sequence complete */
3729   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3730 }
3731
3732 /**
3733  * clutter_actor_continue_paint:
3734  * @self: A #ClutterActor
3735  *
3736  * Run the next stage of the paint sequence. This function should only
3737  * be called within the implementation of the ‘run’ virtual of a
3738  * #ClutterEffect. It will cause the run method of the next effect to
3739  * be applied, or it will paint the actual actor if the current effect
3740  * is the last effect in the chain.
3741  *
3742  * Since: 1.8
3743  */
3744 void
3745 clutter_actor_continue_paint (ClutterActor *self)
3746 {
3747   ClutterActorPrivate *priv;
3748
3749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3750   /* This should only be called from with in the ‘run’ implementation
3751      of a ClutterEffect */
3752   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3753
3754   priv = self->priv;
3755
3756   /* Skip any effects that are disabled */
3757   while (priv->next_effect_to_paint &&
3758          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3759     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3760
3761   /* If this has come from the last effect then we'll just paint the
3762      actual actor */
3763   if (priv->next_effect_to_paint == NULL)
3764     {
3765       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3766         {
3767           ClutterPaintNode *dummy;
3768
3769           /* XXX - this will go away in 2.0, when we can get rid of this
3770            * stuff and switch to a pure retained render tree of PaintNodes
3771            * for the entire frame, starting from the Stage; the paint()
3772            * virtual function can then be called directly.
3773            */
3774           dummy = _clutter_dummy_node_new (self);
3775           clutter_paint_node_set_name (dummy, "Root");
3776
3777           /* XXX - for 1.12, we use the return value of paint_node() to
3778            * decide whether we should emit the ::paint signal.
3779            */
3780           clutter_actor_paint_node (self, dummy);
3781           clutter_paint_node_unref (dummy);
3782
3783           g_signal_emit (self, actor_signals[PAINT], 0);
3784         }
3785       else
3786         {
3787           ClutterColor col = { 0, };
3788
3789           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3790
3791           /* Actor will then paint silhouette of itself in supplied
3792            * color.  See clutter_stage_get_actor_at_pos() for where
3793            * picking is enabled.
3794            */
3795           g_signal_emit (self, actor_signals[PICK], 0, &col);
3796         }
3797     }
3798   else
3799     {
3800       ClutterEffect *old_current_effect;
3801       ClutterEffectPaintFlags run_flags = 0;
3802
3803       /* Cache the current effect so that we can put it back before
3804          returning */
3805       old_current_effect = priv->current_effect;
3806
3807       priv->current_effect = priv->next_effect_to_paint->data;
3808       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3809
3810       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3811         {
3812           if (priv->is_dirty)
3813             {
3814               /* If there's an effect queued with this redraw then all
3815                  effects up to that one will be considered dirty. It
3816                  is expected the queued effect will paint the cached
3817                  image and not call clutter_actor_continue_paint again
3818                  (although it should work ok if it does) */
3819               if (priv->effect_to_redraw == NULL ||
3820                   priv->current_effect != priv->effect_to_redraw)
3821                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3822             }
3823
3824           _clutter_effect_paint (priv->current_effect, run_flags);
3825         }
3826       else
3827         {
3828           /* We can't determine when an actor has been modified since
3829              its last pick so lets just assume it has always been
3830              modified */
3831           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3832
3833           _clutter_effect_pick (priv->current_effect, run_flags);
3834         }
3835
3836       priv->current_effect = old_current_effect;
3837     }
3838 }
3839
3840 static void
3841 _clutter_actor_stop_transitions (ClutterActor *self)
3842 {
3843   const ClutterAnimationInfo *info;
3844   GHashTableIter iter;
3845   gpointer value;
3846
3847   info = _clutter_actor_get_animation_info_or_defaults (self);
3848   if (info->transitions == NULL)
3849     return;
3850
3851   g_hash_table_iter_init (&iter, info->transitions);
3852   while (g_hash_table_iter_next (&iter, NULL, &value))
3853     {
3854       TransitionClosure *closure = value;
3855       clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3856     }
3857 }
3858
3859 static ClutterActorTraverseVisitFlags
3860 invalidate_queue_redraw_entry (ClutterActor *self,
3861                                int           depth,
3862                                gpointer      user_data)
3863 {
3864   ClutterActorPrivate *priv = self->priv;
3865
3866   if (priv->queue_redraw_entry != NULL)
3867     {
3868       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3869       priv->queue_redraw_entry = NULL;
3870     }
3871
3872   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3873 }
3874
3875 static inline void
3876 remove_child (ClutterActor *self,
3877               ClutterActor *child)
3878 {
3879   ClutterActor *prev_sibling, *next_sibling;
3880
3881   prev_sibling = child->priv->prev_sibling;
3882   next_sibling = child->priv->next_sibling;
3883
3884   if (prev_sibling != NULL)
3885     prev_sibling->priv->next_sibling = next_sibling;
3886
3887   if (next_sibling != NULL)
3888     next_sibling->priv->prev_sibling = prev_sibling;
3889
3890   if (self->priv->first_child == child)
3891     self->priv->first_child = next_sibling;
3892
3893   if (self->priv->last_child == child)
3894     self->priv->last_child = prev_sibling;
3895
3896   child->priv->parent = NULL;
3897   child->priv->prev_sibling = NULL;
3898   child->priv->next_sibling = NULL;
3899 }
3900
3901 typedef enum {
3902   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3903   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3904   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3905   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3906   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3907   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3908   REMOVE_CHILD_STOP_TRANSITIONS   = 1 << 6,
3909
3910   /* default flags for public API */
3911   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_STOP_TRANSITIONS |
3912                                     REMOVE_CHILD_DESTROY_META |
3913                                     REMOVE_CHILD_EMIT_PARENT_SET |
3914                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3915                                     REMOVE_CHILD_CHECK_STATE |
3916                                     REMOVE_CHILD_FLUSH_QUEUE |
3917                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3918
3919   /* flags for legacy/deprecated API */
3920   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_STOP_TRANSITIONS |
3921                                     REMOVE_CHILD_CHECK_STATE |
3922                                     REMOVE_CHILD_FLUSH_QUEUE |
3923                                     REMOVE_CHILD_EMIT_PARENT_SET |
3924                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3925 } ClutterActorRemoveChildFlags;
3926
3927 /*< private >
3928  * clutter_actor_remove_child_internal:
3929  * @self: a #ClutterActor
3930  * @child: the child of @self that has to be removed
3931  * @flags: control the removal operations
3932  *
3933  * Removes @child from the list of children of @self.
3934  */
3935 static void
3936 clutter_actor_remove_child_internal (ClutterActor                 *self,
3937                                      ClutterActor                 *child,
3938                                      ClutterActorRemoveChildFlags  flags)
3939 {
3940   ClutterActor *old_first, *old_last;
3941   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3942   gboolean flush_queue;
3943   gboolean notify_first_last;
3944   gboolean was_mapped;
3945   gboolean stop_transitions;
3946
3947   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3948   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3949   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3950   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3951   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3952   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3953   stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3954
3955   g_object_freeze_notify (G_OBJECT (self));
3956
3957   if (stop_transitions)
3958     _clutter_actor_stop_transitions (child);
3959
3960   if (destroy_meta)
3961     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3962
3963   if (check_state)
3964     {
3965       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3966
3967       /* we need to unrealize *before* we set parent_actor to NULL,
3968        * because in an unrealize method actors are dissociating from the
3969        * stage, which means they need to be able to
3970        * clutter_actor_get_stage().
3971        *
3972        * yhis should unmap and unrealize, unless we're reparenting.
3973        */
3974       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3975     }
3976   else
3977     was_mapped = FALSE;
3978
3979   if (flush_queue)
3980     {
3981       /* We take this opportunity to invalidate any queue redraw entry
3982        * associated with the actor and descendants since we won't be able to
3983        * determine the appropriate stage after this.
3984        *
3985        * we do this after we updated the mapped state because actors might
3986        * end up queueing redraws inside their mapped/unmapped virtual
3987        * functions, and if we invalidate the redraw entry we could end up
3988        * with an inconsistent state and weird memory corruption. see
3989        * bugs:
3990        *
3991        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3992        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3993        */
3994       _clutter_actor_traverse (child,
3995                                0,
3996                                invalidate_queue_redraw_entry,
3997                                NULL,
3998                                NULL);
3999     }
4000
4001   old_first = self->priv->first_child;
4002   old_last = self->priv->last_child;
4003
4004   remove_child (self, child);
4005
4006   self->priv->n_children -= 1;
4007
4008   self->priv->age += 1;
4009
4010   /* if the child that got removed was visible and set to
4011    * expand then we want to reset the parent's state in
4012    * case the child was the only thing that was making it
4013    * expand.
4014    */
4015   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
4016       (child->priv->needs_compute_expand ||
4017        child->priv->needs_x_expand ||
4018        child->priv->needs_y_expand))
4019     {
4020       clutter_actor_queue_compute_expand (self);
4021     }
4022
4023   /* clutter_actor_reparent() will emit ::parent-set for us */
4024   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
4025     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4026
4027   /* if the child was mapped then we need to relayout ourselves to account
4028    * for the removed child
4029    */
4030   if (was_mapped)
4031     clutter_actor_queue_relayout (self);
4032
4033   /* we need to emit the signal before dropping the reference */
4034   if (emit_actor_removed)
4035     g_signal_emit_by_name (self, "actor-removed", child);
4036
4037   if (notify_first_last)
4038     {
4039       if (old_first != self->priv->first_child)
4040         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4041
4042       if (old_last != self->priv->last_child)
4043         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4044     }
4045
4046   g_object_thaw_notify (G_OBJECT (self));
4047
4048   /* remove the reference we acquired in clutter_actor_add_child() */
4049   g_object_unref (child);
4050 }
4051
4052 static const ClutterTransformInfo default_transform_info = {
4053   0.0, { 0, },          /* rotation-x */
4054   0.0, { 0, },          /* rotation-y */
4055   0.0, { 0, },          /* rotation-z */
4056
4057   1.0, 1.0, { 0, },     /* scale */
4058
4059   { 0, },               /* anchor */
4060
4061   0.0,                  /* depth */
4062 };
4063
4064 /*< private >
4065  * _clutter_actor_get_transform_info_or_defaults:
4066  * @self: a #ClutterActor
4067  *
4068  * Retrieves the ClutterTransformInfo structure associated to an actor.
4069  *
4070  * If the actor does not have a ClutterTransformInfo structure associated
4071  * to it, then the default structure will be returned.
4072  *
4073  * This function should only be used for getters.
4074  *
4075  * Return value: a const pointer to the ClutterTransformInfo structure
4076  */
4077 const ClutterTransformInfo *
4078 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4079 {
4080   ClutterTransformInfo *info;
4081
4082   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4083   if (info != NULL)
4084     return info;
4085
4086   return &default_transform_info;
4087 }
4088
4089 static void
4090 clutter_transform_info_free (gpointer data)
4091 {
4092   if (data != NULL)
4093     g_slice_free (ClutterTransformInfo, data);
4094 }
4095
4096 /*< private >
4097  * _clutter_actor_get_transform_info:
4098  * @self: a #ClutterActor
4099  *
4100  * Retrieves a pointer to the ClutterTransformInfo structure.
4101  *
4102  * If the actor does not have a ClutterTransformInfo associated to it, one
4103  * will be created and initialized to the default values.
4104  *
4105  * This function should be used for setters.
4106  *
4107  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4108  * instead.
4109  *
4110  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4111  *   structure
4112  */
4113 ClutterTransformInfo *
4114 _clutter_actor_get_transform_info (ClutterActor *self)
4115 {
4116   ClutterTransformInfo *info;
4117
4118   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4119   if (info == NULL)
4120     {
4121       info = g_slice_new (ClutterTransformInfo);
4122
4123       *info = default_transform_info;
4124
4125       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4126                                info,
4127                                clutter_transform_info_free);
4128     }
4129
4130   return info;
4131 }
4132
4133 /*< private >
4134  * clutter_actor_set_rotation_angle_internal:
4135  * @self: a #ClutterActor
4136  * @axis: the axis of the angle to change
4137  * @angle: the angle of rotation
4138  *
4139  * Sets the rotation angle on the given axis without affecting the
4140  * rotation center point.
4141  */
4142 static inline void
4143 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4144                                            ClutterRotateAxis  axis,
4145                                            gdouble            angle)
4146 {
4147   GObject *obj = G_OBJECT (self);
4148   ClutterTransformInfo *info;
4149
4150   info = _clutter_actor_get_transform_info (self);
4151
4152   g_object_freeze_notify (obj);
4153
4154   switch (axis)
4155     {
4156     case CLUTTER_X_AXIS:
4157       info->rx_angle = angle;
4158       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4159       break;
4160
4161     case CLUTTER_Y_AXIS:
4162       info->ry_angle = angle;
4163       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4164       break;
4165
4166     case CLUTTER_Z_AXIS:
4167       info->rz_angle = angle;
4168       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4169       break;
4170     }
4171
4172   self->priv->transform_valid = FALSE;
4173
4174   g_object_thaw_notify (obj);
4175
4176   clutter_actor_queue_redraw (self);
4177 }
4178
4179 static inline void
4180 clutter_actor_set_rotation_angle (ClutterActor      *self,
4181                                   ClutterRotateAxis  axis,
4182                                   gdouble            angle)
4183 {
4184   const ClutterTransformInfo *info;
4185   const double *cur_angle_p = NULL;
4186   GParamSpec *pspec = NULL;
4187
4188   info = _clutter_actor_get_transform_info_or_defaults (self);
4189
4190   switch (axis)
4191     {
4192     case CLUTTER_X_AXIS:
4193       cur_angle_p = &info->rx_angle;
4194       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4195       break;
4196
4197     case CLUTTER_Y_AXIS:
4198       cur_angle_p = &info->ry_angle;
4199       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4200       break;
4201
4202     case CLUTTER_Z_AXIS:
4203       cur_angle_p = &info->rz_angle;
4204       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4205       break;
4206     }
4207
4208   g_assert (pspec != NULL);
4209   g_assert (cur_angle_p != NULL);
4210
4211   if (_clutter_actor_get_transition (self, pspec) == NULL)
4212     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4213   else
4214     _clutter_actor_update_transition (self, pspec, angle);
4215
4216   clutter_actor_queue_redraw (self);
4217 }
4218
4219 /*< private >
4220  * clutter_actor_set_rotation_center_internal:
4221  * @self: a #ClutterActor
4222  * @axis: the axis of the center to change
4223  * @center: the coordinates of the rotation center
4224  *
4225  * Sets the rotation center on the given axis without affecting the
4226  * rotation angle.
4227  */
4228 static inline void
4229 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4230                                             ClutterRotateAxis    axis,
4231                                             const ClutterVertex *center)
4232 {
4233   GObject *obj = G_OBJECT (self);
4234   ClutterTransformInfo *info;
4235   ClutterVertex v = { 0, 0, 0 };
4236
4237   info = _clutter_actor_get_transform_info (self);
4238
4239   if (center != NULL)
4240     v = *center;
4241
4242   g_object_freeze_notify (obj);
4243
4244   switch (axis)
4245     {
4246     case CLUTTER_X_AXIS:
4247       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4248       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4249       break;
4250
4251     case CLUTTER_Y_AXIS:
4252       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4253       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4254       break;
4255
4256     case CLUTTER_Z_AXIS:
4257       /* if the previously set rotation center was fractional, then
4258        * setting explicit coordinates will have to notify the
4259        * :rotation-center-z-gravity property as well
4260        */
4261       if (info->rz_center.is_fractional)
4262         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4263
4264       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4265       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4266       break;
4267     }
4268
4269   self->priv->transform_valid = FALSE;
4270
4271   g_object_thaw_notify (obj);
4272
4273   clutter_actor_queue_redraw (self);
4274 }
4275
4276 static void
4277 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4278                                          double factor,
4279                                          GParamSpec *pspec)
4280 {
4281   GObject *obj = G_OBJECT (self);
4282   ClutterTransformInfo *info;
4283
4284   info = _clutter_actor_get_transform_info (self);
4285
4286   if (pspec == obj_props[PROP_SCALE_X])
4287     info->scale_x = factor;
4288   else
4289     info->scale_y = factor;
4290
4291   self->priv->transform_valid = FALSE;
4292   clutter_actor_queue_redraw (self);
4293   g_object_notify_by_pspec (obj, pspec);
4294 }
4295
4296 static inline void
4297 clutter_actor_set_scale_factor (ClutterActor      *self,
4298                                 ClutterRotateAxis  axis,
4299                                 gdouble            factor)
4300 {
4301   const ClutterTransformInfo *info;
4302   const double *scale_p = NULL;
4303   GParamSpec *pspec = NULL;
4304
4305   info = _clutter_actor_get_transform_info_or_defaults (self);
4306
4307   switch (axis)
4308     {
4309     case CLUTTER_X_AXIS:
4310       pspec = obj_props[PROP_SCALE_X];
4311       scale_p = &info->scale_x;
4312       break;
4313
4314     case CLUTTER_Y_AXIS:
4315       pspec = obj_props[PROP_SCALE_Y];
4316       scale_p = &info->scale_y;
4317       break;
4318
4319     case CLUTTER_Z_AXIS:
4320       break;
4321     }
4322
4323   g_assert (pspec != NULL);
4324   g_assert (scale_p != NULL);
4325
4326   if (_clutter_actor_get_transition (self, pspec) == NULL)
4327     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4328   else
4329     _clutter_actor_update_transition (self, pspec, factor);
4330
4331   clutter_actor_queue_redraw (self);
4332 }
4333
4334 static inline void
4335 clutter_actor_set_scale_center (ClutterActor      *self,
4336                                 ClutterRotateAxis  axis,
4337                                 gfloat             coord)
4338 {
4339   GObject *obj = G_OBJECT (self);
4340   ClutterTransformInfo *info;
4341   gfloat center_x, center_y;
4342
4343   info = _clutter_actor_get_transform_info (self);
4344
4345   g_object_freeze_notify (obj);
4346
4347   /* get the current scale center coordinates */
4348   clutter_anchor_coord_get_units (self, &info->scale_center,
4349                                   &center_x,
4350                                   &center_y,
4351                                   NULL);
4352
4353   /* we need to notify this too, because setting explicit coordinates will
4354    * change the gravity as a side effect
4355    */
4356   if (info->scale_center.is_fractional)
4357     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4358
4359   switch (axis)
4360     {
4361     case CLUTTER_X_AXIS:
4362       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4363       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4364       break;
4365
4366     case CLUTTER_Y_AXIS:
4367       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4368       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4369       break;
4370
4371     default:
4372       g_assert_not_reached ();
4373     }
4374
4375   self->priv->transform_valid = FALSE;
4376
4377   clutter_actor_queue_redraw (self);
4378
4379   g_object_thaw_notify (obj);
4380 }
4381
4382 static inline void
4383 clutter_actor_set_scale_gravity (ClutterActor   *self,
4384                                  ClutterGravity  gravity)
4385 {
4386   ClutterTransformInfo *info;
4387   GObject *obj;
4388
4389   info = _clutter_actor_get_transform_info (self);
4390   obj = G_OBJECT (self);
4391
4392   if (gravity == CLUTTER_GRAVITY_NONE)
4393     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4394   else
4395     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4396
4397   self->priv->transform_valid = FALSE;
4398
4399   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4400   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4401   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4402
4403   clutter_actor_queue_redraw (self);
4404 }
4405
4406 static inline void
4407 clutter_actor_set_anchor_coord (ClutterActor      *self,
4408                                 ClutterRotateAxis  axis,
4409                                 gfloat             coord)
4410 {
4411   GObject *obj = G_OBJECT (self);
4412   ClutterTransformInfo *info;
4413   gfloat anchor_x, anchor_y;
4414
4415   info = _clutter_actor_get_transform_info (self);
4416
4417   g_object_freeze_notify (obj);
4418
4419   clutter_anchor_coord_get_units (self, &info->anchor,
4420                                   &anchor_x,
4421                                   &anchor_y,
4422                                   NULL);
4423
4424   if (info->anchor.is_fractional)
4425     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4426
4427   switch (axis)
4428     {
4429     case CLUTTER_X_AXIS:
4430       clutter_anchor_coord_set_units (&info->anchor,
4431                                       coord,
4432                                       anchor_y,
4433                                       0.0);
4434       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4435       break;
4436
4437     case CLUTTER_Y_AXIS:
4438       clutter_anchor_coord_set_units (&info->anchor,
4439                                       anchor_x,
4440                                       coord,
4441                                       0.0);
4442       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4443       break;
4444
4445     default:
4446       g_assert_not_reached ();
4447     }
4448
4449   self->priv->transform_valid = FALSE;
4450
4451   clutter_actor_queue_redraw (self);
4452
4453   g_object_thaw_notify (obj);
4454 }
4455
4456 static void
4457 clutter_actor_set_property (GObject      *object,
4458                             guint         prop_id,
4459                             const GValue *value,
4460                             GParamSpec   *pspec)
4461 {
4462   ClutterActor *actor = CLUTTER_ACTOR (object);
4463   ClutterActorPrivate *priv = actor->priv;
4464
4465   switch (prop_id)
4466     {
4467     case PROP_X:
4468       clutter_actor_set_x (actor, g_value_get_float (value));
4469       break;
4470
4471     case PROP_Y:
4472       clutter_actor_set_y (actor, g_value_get_float (value));
4473       break;
4474
4475     case PROP_POSITION:
4476       {
4477         const ClutterPoint *pos = g_value_get_boxed (value);
4478
4479         if (pos != NULL)
4480           clutter_actor_set_position (actor, pos->x, pos->y);
4481         else
4482           clutter_actor_set_fixed_position_set (actor, FALSE);
4483       }
4484       break;
4485
4486     case PROP_WIDTH:
4487       clutter_actor_set_width (actor, g_value_get_float (value));
4488       break;
4489
4490     case PROP_HEIGHT:
4491       clutter_actor_set_height (actor, g_value_get_float (value));
4492       break;
4493
4494     case PROP_SIZE:
4495       {
4496         const ClutterSize *size = g_value_get_boxed (value);
4497
4498         if (size != NULL)
4499           clutter_actor_set_size (actor, size->width, size->height);
4500         else
4501           clutter_actor_set_size (actor, -1, -1);
4502       }
4503       break;
4504
4505     case PROP_FIXED_X:
4506       clutter_actor_set_x (actor, g_value_get_float (value));
4507       break;
4508
4509     case PROP_FIXED_Y:
4510       clutter_actor_set_y (actor, g_value_get_float (value));
4511       break;
4512
4513     case PROP_FIXED_POSITION_SET:
4514       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4515       break;
4516
4517     case PROP_MIN_WIDTH:
4518       clutter_actor_set_min_width (actor, g_value_get_float (value));
4519       break;
4520
4521     case PROP_MIN_HEIGHT:
4522       clutter_actor_set_min_height (actor, g_value_get_float (value));
4523       break;
4524
4525     case PROP_NATURAL_WIDTH:
4526       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4527       break;
4528
4529     case PROP_NATURAL_HEIGHT:
4530       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4531       break;
4532
4533     case PROP_MIN_WIDTH_SET:
4534       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4535       break;
4536
4537     case PROP_MIN_HEIGHT_SET:
4538       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4539       break;
4540
4541     case PROP_NATURAL_WIDTH_SET:
4542       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4543       break;
4544
4545     case PROP_NATURAL_HEIGHT_SET:
4546       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4547       break;
4548
4549     case PROP_REQUEST_MODE:
4550       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4551       break;
4552
4553     case PROP_DEPTH:
4554       clutter_actor_set_depth (actor, g_value_get_float (value));
4555       break;
4556
4557     case PROP_OPACITY:
4558       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4559       break;
4560
4561     case PROP_OFFSCREEN_REDIRECT:
4562       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4563       break;
4564
4565     case PROP_NAME:
4566       clutter_actor_set_name (actor, g_value_get_string (value));
4567       break;
4568
4569     case PROP_VISIBLE:
4570       if (g_value_get_boolean (value) == TRUE)
4571         clutter_actor_show (actor);
4572       else
4573         clutter_actor_hide (actor);
4574       break;
4575
4576     case PROP_SCALE_X:
4577       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4578                                       g_value_get_double (value));
4579       break;
4580
4581     case PROP_SCALE_Y:
4582       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4583                                       g_value_get_double (value));
4584       break;
4585
4586     case PROP_SCALE_CENTER_X:
4587       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4588                                       g_value_get_float (value));
4589       break;
4590
4591     case PROP_SCALE_CENTER_Y:
4592       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4593                                       g_value_get_float (value));
4594       break;
4595
4596     case PROP_SCALE_GRAVITY:
4597       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4598       break;
4599
4600     case PROP_CLIP:
4601       {
4602         const ClutterGeometry *geom = g_value_get_boxed (value);
4603
4604         clutter_actor_set_clip (actor,
4605                                 geom->x, geom->y,
4606                                 geom->width, geom->height);
4607       }
4608       break;
4609
4610     case PROP_CLIP_TO_ALLOCATION:
4611       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4612       break;
4613
4614     case PROP_REACTIVE:
4615       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4616       break;
4617
4618     case PROP_ROTATION_ANGLE_X:
4619       clutter_actor_set_rotation_angle (actor,
4620                                         CLUTTER_X_AXIS,
4621                                         g_value_get_double (value));
4622       break;
4623
4624     case PROP_ROTATION_ANGLE_Y:
4625       clutter_actor_set_rotation_angle (actor,
4626                                         CLUTTER_Y_AXIS,
4627                                         g_value_get_double (value));
4628       break;
4629
4630     case PROP_ROTATION_ANGLE_Z:
4631       clutter_actor_set_rotation_angle (actor,
4632                                         CLUTTER_Z_AXIS,
4633                                         g_value_get_double (value));
4634       break;
4635
4636     case PROP_ROTATION_CENTER_X:
4637       clutter_actor_set_rotation_center_internal (actor,
4638                                                   CLUTTER_X_AXIS,
4639                                                   g_value_get_boxed (value));
4640       break;
4641
4642     case PROP_ROTATION_CENTER_Y:
4643       clutter_actor_set_rotation_center_internal (actor,
4644                                                   CLUTTER_Y_AXIS,
4645                                                   g_value_get_boxed (value));
4646       break;
4647
4648     case PROP_ROTATION_CENTER_Z:
4649       clutter_actor_set_rotation_center_internal (actor,
4650                                                   CLUTTER_Z_AXIS,
4651                                                   g_value_get_boxed (value));
4652       break;
4653
4654     case PROP_ROTATION_CENTER_Z_GRAVITY:
4655       {
4656         const ClutterTransformInfo *info;
4657
4658         info = _clutter_actor_get_transform_info_or_defaults (actor);
4659         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4660                                                    g_value_get_enum (value));
4661       }
4662       break;
4663
4664     case PROP_ANCHOR_X:
4665       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4666                                       g_value_get_float (value));
4667       break;
4668
4669     case PROP_ANCHOR_Y:
4670       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4671                                       g_value_get_float (value));
4672       break;
4673
4674     case PROP_ANCHOR_GRAVITY:
4675       clutter_actor_set_anchor_point_from_gravity (actor,
4676                                                    g_value_get_enum (value));
4677       break;
4678
4679     case PROP_SHOW_ON_SET_PARENT:
4680       priv->show_on_set_parent = g_value_get_boolean (value);
4681       break;
4682
4683     case PROP_TEXT_DIRECTION:
4684       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4685       break;
4686
4687     case PROP_ACTIONS:
4688       clutter_actor_add_action (actor, g_value_get_object (value));
4689       break;
4690
4691     case PROP_CONSTRAINTS:
4692       clutter_actor_add_constraint (actor, g_value_get_object (value));
4693       break;
4694
4695     case PROP_EFFECT:
4696       clutter_actor_add_effect (actor, g_value_get_object (value));
4697       break;
4698
4699     case PROP_LAYOUT_MANAGER:
4700       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4701       break;
4702
4703     case PROP_X_EXPAND:
4704       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4705       break;
4706
4707     case PROP_Y_EXPAND:
4708       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4709       break;
4710
4711     case PROP_X_ALIGN:
4712       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4713       break;
4714
4715     case PROP_Y_ALIGN:
4716       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4717       break;
4718
4719     case PROP_MARGIN_TOP:
4720       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4721       break;
4722
4723     case PROP_MARGIN_BOTTOM:
4724       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4725       break;
4726
4727     case PROP_MARGIN_LEFT:
4728       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4729       break;
4730
4731     case PROP_MARGIN_RIGHT:
4732       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4733       break;
4734
4735     case PROP_BACKGROUND_COLOR:
4736       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4737       break;
4738
4739     case PROP_CONTENT:
4740       clutter_actor_set_content (actor, g_value_get_object (value));
4741       break;
4742
4743     case PROP_CONTENT_GRAVITY:
4744       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4745       break;
4746
4747     case PROP_MINIFICATION_FILTER:
4748       clutter_actor_set_content_scaling_filters (actor,
4749                                                  g_value_get_enum (value),
4750                                                  actor->priv->mag_filter);
4751       break;
4752
4753     case PROP_MAGNIFICATION_FILTER:
4754       clutter_actor_set_content_scaling_filters (actor,
4755                                                  actor->priv->min_filter,
4756                                                  g_value_get_enum (value));
4757       break;
4758
4759     case PROP_CONTENT_REPEAT:
4760       clutter_actor_set_content_repeat (actor, g_value_get_flags (value));
4761       break;
4762
4763     default:
4764       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4765       break;
4766     }
4767 }
4768
4769 static void
4770 clutter_actor_get_property (GObject    *object,
4771                             guint       prop_id,
4772                             GValue     *value,
4773                             GParamSpec *pspec)
4774 {
4775   ClutterActor *actor = CLUTTER_ACTOR (object);
4776   ClutterActorPrivate *priv = actor->priv;
4777
4778   switch (prop_id)
4779     {
4780     case PROP_X:
4781       g_value_set_float (value, clutter_actor_get_x (actor));
4782       break;
4783
4784     case PROP_Y:
4785       g_value_set_float (value, clutter_actor_get_y (actor));
4786       break;
4787
4788     case PROP_POSITION:
4789       {
4790         ClutterPoint position;
4791
4792         clutter_point_init (&position,
4793                             clutter_actor_get_x (actor),
4794                             clutter_actor_get_y (actor));
4795         g_value_set_boxed (value, &position);
4796       }
4797       break;
4798
4799     case PROP_WIDTH:
4800       g_value_set_float (value, clutter_actor_get_width (actor));
4801       break;
4802
4803     case PROP_HEIGHT:
4804       g_value_set_float (value, clutter_actor_get_height (actor));
4805       break;
4806
4807     case PROP_SIZE:
4808       {
4809         ClutterSize size;
4810
4811         clutter_size_init (&size,
4812                            clutter_actor_get_width (actor),
4813                            clutter_actor_get_height (actor));
4814         g_value_set_boxed (value, &size);
4815       }
4816       break;
4817
4818     case PROP_FIXED_X:
4819       {
4820         const ClutterLayoutInfo *info;
4821
4822         info = _clutter_actor_get_layout_info_or_defaults (actor);
4823         g_value_set_float (value, info->fixed_pos.x);
4824       }
4825       break;
4826
4827     case PROP_FIXED_Y:
4828       {
4829         const ClutterLayoutInfo *info;
4830
4831         info = _clutter_actor_get_layout_info_or_defaults (actor);
4832         g_value_set_float (value, info->fixed_pos.y);
4833       }
4834       break;
4835
4836     case PROP_FIXED_POSITION_SET:
4837       g_value_set_boolean (value, priv->position_set);
4838       break;
4839
4840     case PROP_MIN_WIDTH:
4841       {
4842         const ClutterLayoutInfo *info;
4843
4844         info = _clutter_actor_get_layout_info_or_defaults (actor);
4845         g_value_set_float (value, info->minimum.width);
4846       }
4847       break;
4848
4849     case PROP_MIN_HEIGHT:
4850       {
4851         const ClutterLayoutInfo *info;
4852
4853         info = _clutter_actor_get_layout_info_or_defaults (actor);
4854         g_value_set_float (value, info->minimum.height);
4855       }
4856       break;
4857
4858     case PROP_NATURAL_WIDTH:
4859       {
4860         const ClutterLayoutInfo *info;
4861
4862         info = _clutter_actor_get_layout_info_or_defaults (actor);
4863         g_value_set_float (value, info->natural.width);
4864       }
4865       break;
4866
4867     case PROP_NATURAL_HEIGHT:
4868       {
4869         const ClutterLayoutInfo *info;
4870
4871         info = _clutter_actor_get_layout_info_or_defaults (actor);
4872         g_value_set_float (value, info->natural.height);
4873       }
4874       break;
4875
4876     case PROP_MIN_WIDTH_SET:
4877       g_value_set_boolean (value, priv->min_width_set);
4878       break;
4879
4880     case PROP_MIN_HEIGHT_SET:
4881       g_value_set_boolean (value, priv->min_height_set);
4882       break;
4883
4884     case PROP_NATURAL_WIDTH_SET:
4885       g_value_set_boolean (value, priv->natural_width_set);
4886       break;
4887
4888     case PROP_NATURAL_HEIGHT_SET:
4889       g_value_set_boolean (value, priv->natural_height_set);
4890       break;
4891
4892     case PROP_REQUEST_MODE:
4893       g_value_set_enum (value, priv->request_mode);
4894       break;
4895
4896     case PROP_ALLOCATION:
4897       g_value_set_boxed (value, &priv->allocation);
4898       break;
4899
4900     case PROP_DEPTH:
4901       g_value_set_float (value, clutter_actor_get_depth (actor));
4902       break;
4903
4904     case PROP_OPACITY:
4905       g_value_set_uint (value, priv->opacity);
4906       break;
4907
4908     case PROP_OFFSCREEN_REDIRECT:
4909       g_value_set_enum (value, priv->offscreen_redirect);
4910       break;
4911
4912     case PROP_NAME:
4913       g_value_set_string (value, priv->name);
4914       break;
4915
4916     case PROP_VISIBLE:
4917       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4918       break;
4919
4920     case PROP_MAPPED:
4921       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4922       break;
4923
4924     case PROP_REALIZED:
4925       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4926       break;
4927
4928     case PROP_HAS_CLIP:
4929       g_value_set_boolean (value, priv->has_clip);
4930       break;
4931
4932     case PROP_CLIP:
4933       {
4934         ClutterGeometry clip;
4935
4936         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4937         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4938         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4939         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4940
4941         g_value_set_boxed (value, &clip);
4942       }
4943       break;
4944
4945     case PROP_CLIP_TO_ALLOCATION:
4946       g_value_set_boolean (value, priv->clip_to_allocation);
4947       break;
4948
4949     case PROP_SCALE_X:
4950       {
4951         const ClutterTransformInfo *info;
4952
4953         info = _clutter_actor_get_transform_info_or_defaults (actor);
4954         g_value_set_double (value, info->scale_x);
4955       }
4956       break;
4957
4958     case PROP_SCALE_Y:
4959       {
4960         const ClutterTransformInfo *info;
4961
4962         info = _clutter_actor_get_transform_info_or_defaults (actor);
4963         g_value_set_double (value, info->scale_y);
4964       }
4965       break;
4966
4967     case PROP_SCALE_CENTER_X:
4968       {
4969         gfloat center;
4970
4971         clutter_actor_get_scale_center (actor, &center, NULL);
4972
4973         g_value_set_float (value, center);
4974       }
4975       break;
4976
4977     case PROP_SCALE_CENTER_Y:
4978       {
4979         gfloat center;
4980
4981         clutter_actor_get_scale_center (actor, NULL, &center);
4982
4983         g_value_set_float (value, center);
4984       }
4985       break;
4986
4987     case PROP_SCALE_GRAVITY:
4988       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4989       break;
4990
4991     case PROP_REACTIVE:
4992       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4993       break;
4994
4995     case PROP_ROTATION_ANGLE_X:
4996       {
4997         const ClutterTransformInfo *info;
4998
4999         info = _clutter_actor_get_transform_info_or_defaults (actor);
5000         g_value_set_double (value, info->rx_angle);
5001       }
5002       break;
5003
5004     case PROP_ROTATION_ANGLE_Y:
5005       {
5006         const ClutterTransformInfo *info;
5007
5008         info = _clutter_actor_get_transform_info_or_defaults (actor);
5009         g_value_set_double (value, info->ry_angle);
5010       }
5011       break;
5012
5013     case PROP_ROTATION_ANGLE_Z:
5014       {
5015         const ClutterTransformInfo *info;
5016
5017         info = _clutter_actor_get_transform_info_or_defaults (actor);
5018         g_value_set_double (value, info->rz_angle);
5019       }
5020       break;
5021
5022     case PROP_ROTATION_CENTER_X:
5023       {
5024         ClutterVertex center;
5025
5026         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5027                                     &center.x,
5028                                     &center.y,
5029                                     &center.z);
5030
5031         g_value_set_boxed (value, &center);
5032       }
5033       break;
5034
5035     case PROP_ROTATION_CENTER_Y:
5036       {
5037         ClutterVertex center;
5038
5039         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5040                                     &center.x,
5041                                     &center.y,
5042                                     &center.z);
5043
5044         g_value_set_boxed (value, &center);
5045       }
5046       break;
5047
5048     case PROP_ROTATION_CENTER_Z:
5049       {
5050         ClutterVertex center;
5051
5052         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5053                                     &center.x,
5054                                     &center.y,
5055                                     &center.z);
5056
5057         g_value_set_boxed (value, &center);
5058       }
5059       break;
5060
5061     case PROP_ROTATION_CENTER_Z_GRAVITY:
5062       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5063       break;
5064
5065     case PROP_ANCHOR_X:
5066       {
5067         const ClutterTransformInfo *info;
5068         gfloat anchor_x;
5069
5070         info = _clutter_actor_get_transform_info_or_defaults (actor);
5071         clutter_anchor_coord_get_units (actor, &info->anchor,
5072                                         &anchor_x,
5073                                         NULL,
5074                                         NULL);
5075         g_value_set_float (value, anchor_x);
5076       }
5077       break;
5078
5079     case PROP_ANCHOR_Y:
5080       {
5081         const ClutterTransformInfo *info;
5082         gfloat anchor_y;
5083
5084         info = _clutter_actor_get_transform_info_or_defaults (actor);
5085         clutter_anchor_coord_get_units (actor, &info->anchor,
5086                                         NULL,
5087                                         &anchor_y,
5088                                         NULL);
5089         g_value_set_float (value, anchor_y);
5090       }
5091       break;
5092
5093     case PROP_ANCHOR_GRAVITY:
5094       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5095       break;
5096
5097     case PROP_SHOW_ON_SET_PARENT:
5098       g_value_set_boolean (value, priv->show_on_set_parent);
5099       break;
5100
5101     case PROP_TEXT_DIRECTION:
5102       g_value_set_enum (value, priv->text_direction);
5103       break;
5104
5105     case PROP_HAS_POINTER:
5106       g_value_set_boolean (value, priv->has_pointer);
5107       break;
5108
5109     case PROP_LAYOUT_MANAGER:
5110       g_value_set_object (value, priv->layout_manager);
5111       break;
5112
5113     case PROP_X_EXPAND:
5114       {
5115         const ClutterLayoutInfo *info;
5116
5117         info = _clutter_actor_get_layout_info_or_defaults (actor);
5118         g_value_set_boolean (value, info->x_expand);
5119       }
5120       break;
5121
5122     case PROP_Y_EXPAND:
5123       {
5124         const ClutterLayoutInfo *info;
5125
5126         info = _clutter_actor_get_layout_info_or_defaults (actor);
5127         g_value_set_boolean (value, info->y_expand);
5128       }
5129       break;
5130
5131     case PROP_X_ALIGN:
5132       {
5133         const ClutterLayoutInfo *info;
5134
5135         info = _clutter_actor_get_layout_info_or_defaults (actor);
5136         g_value_set_enum (value, info->x_align);
5137       }
5138       break;
5139
5140     case PROP_Y_ALIGN:
5141       {
5142         const ClutterLayoutInfo *info;
5143
5144         info = _clutter_actor_get_layout_info_or_defaults (actor);
5145         g_value_set_enum (value, info->y_align);
5146       }
5147       break;
5148
5149     case PROP_MARGIN_TOP:
5150       {
5151         const ClutterLayoutInfo *info;
5152
5153         info = _clutter_actor_get_layout_info_or_defaults (actor);
5154         g_value_set_float (value, info->margin.top);
5155       }
5156       break;
5157
5158     case PROP_MARGIN_BOTTOM:
5159       {
5160         const ClutterLayoutInfo *info;
5161
5162         info = _clutter_actor_get_layout_info_or_defaults (actor);
5163         g_value_set_float (value, info->margin.bottom);
5164       }
5165       break;
5166
5167     case PROP_MARGIN_LEFT:
5168       {
5169         const ClutterLayoutInfo *info;
5170
5171         info = _clutter_actor_get_layout_info_or_defaults (actor);
5172         g_value_set_float (value, info->margin.left);
5173       }
5174       break;
5175
5176     case PROP_MARGIN_RIGHT:
5177       {
5178         const ClutterLayoutInfo *info;
5179
5180         info = _clutter_actor_get_layout_info_or_defaults (actor);
5181         g_value_set_float (value, info->margin.right);
5182       }
5183       break;
5184
5185     case PROP_BACKGROUND_COLOR_SET:
5186       g_value_set_boolean (value, priv->bg_color_set);
5187       break;
5188
5189     case PROP_BACKGROUND_COLOR:
5190       g_value_set_boxed (value, &priv->bg_color);
5191       break;
5192
5193     case PROP_FIRST_CHILD:
5194       g_value_set_object (value, priv->first_child);
5195       break;
5196
5197     case PROP_LAST_CHILD:
5198       g_value_set_object (value, priv->last_child);
5199       break;
5200
5201     case PROP_CONTENT:
5202       g_value_set_object (value, priv->content);
5203       break;
5204
5205     case PROP_CONTENT_GRAVITY:
5206       g_value_set_enum (value, priv->content_gravity);
5207       break;
5208
5209     case PROP_CONTENT_BOX:
5210       {
5211         ClutterActorBox box = { 0, };
5212
5213         clutter_actor_get_content_box (actor, &box);
5214         g_value_set_boxed (value, &box);
5215       }
5216       break;
5217
5218     case PROP_MINIFICATION_FILTER:
5219       g_value_set_enum (value, priv->min_filter);
5220       break;
5221
5222     case PROP_MAGNIFICATION_FILTER:
5223       g_value_set_enum (value, priv->mag_filter);
5224       break;
5225
5226     case PROP_CONTENT_REPEAT:
5227       g_value_set_flags (value, priv->content_repeat);
5228       break;
5229
5230     default:
5231       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5232       break;
5233     }
5234 }
5235
5236 static void
5237 clutter_actor_dispose (GObject *object)
5238 {
5239   ClutterActor *self = CLUTTER_ACTOR (object);
5240   ClutterActorPrivate *priv = self->priv;
5241
5242   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5243                 priv->id,
5244                 g_type_name (G_OBJECT_TYPE (self)),
5245                 object->ref_count);
5246
5247   g_signal_emit (self, actor_signals[DESTROY], 0);
5248
5249   /* avoid recursing when called from clutter_actor_destroy() */
5250   if (priv->parent != NULL)
5251     {
5252       ClutterActor *parent = priv->parent;
5253
5254       /* go through the Container implementation unless this
5255        * is an internal child and has been marked as such.
5256        *
5257        * removing the actor from its parent will reset the
5258        * realized and mapped states.
5259        */
5260       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5261         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5262       else
5263         clutter_actor_remove_child_internal (parent, self,
5264                                              REMOVE_CHILD_LEGACY_FLAGS);
5265     }
5266
5267   /* parent must be gone at this point */
5268   g_assert (priv->parent == NULL);
5269
5270   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5271     {
5272       /* can't be mapped or realized with no parent */
5273       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5274       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5275     }
5276
5277   g_clear_object (&priv->pango_context);
5278   g_clear_object (&priv->actions);
5279   g_clear_object (&priv->constraints);
5280   g_clear_object (&priv->effects);
5281   g_clear_object (&priv->flatten_effect);
5282
5283   if (priv->layout_manager != NULL)
5284     {
5285       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5286       g_clear_object (&priv->layout_manager);
5287     }
5288
5289   if (priv->content != NULL)
5290     {
5291       _clutter_content_detached (priv->content, self);
5292       g_clear_object (&priv->content);
5293     }
5294
5295   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5296 }
5297
5298 static void
5299 clutter_actor_finalize (GObject *object)
5300 {
5301   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5302
5303   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5304                 priv->name != NULL ? priv->name : "<none>",
5305                 priv->id,
5306                 g_type_name (G_OBJECT_TYPE (object)));
5307
5308   _clutter_context_release_id (priv->id);
5309
5310   g_free (priv->name);
5311
5312 #ifdef CLUTTER_ENABLE_DEBUG
5313   g_free (priv->debug_name);
5314 #endif
5315
5316   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5317 }
5318
5319
5320 /**
5321  * clutter_actor_get_accessible:
5322  * @self: a #ClutterActor
5323  *
5324  * Returns the accessible object that describes the actor to an
5325  * assistive technology.
5326  *
5327  * If no class-specific #AtkObject implementation is available for the
5328  * actor instance in question, it will inherit an #AtkObject
5329  * implementation from the first ancestor class for which such an
5330  * implementation is defined.
5331  *
5332  * The documentation of the <ulink
5333  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5334  * library contains more information about accessible objects and
5335  * their uses.
5336  *
5337  * Returns: (transfer none): the #AtkObject associated with @actor
5338  */
5339 AtkObject *
5340 clutter_actor_get_accessible (ClutterActor *self)
5341 {
5342   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5343
5344   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5345 }
5346
5347 static AtkObject *
5348 clutter_actor_real_get_accessible (ClutterActor *actor)
5349 {
5350   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5351 }
5352
5353 static AtkObject *
5354 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5355 {
5356   AtkObject *accessible;
5357
5358   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5359   if (accessible != NULL)
5360     g_object_ref (accessible);
5361
5362   return accessible;
5363 }
5364
5365 static void
5366 atk_implementor_iface_init (AtkImplementorIface *iface)
5367 {
5368   iface->ref_accessible = _clutter_actor_ref_accessible;
5369 }
5370
5371 static gboolean
5372 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5373                                            ClutterPaintVolume *volume)
5374 {
5375   ClutterActorPrivate *priv = self->priv;
5376   gboolean res = TRUE;
5377
5378   /* we start from the allocation */
5379   clutter_paint_volume_set_width (volume,
5380                                   priv->allocation.x2 - priv->allocation.x1);
5381   clutter_paint_volume_set_height (volume,
5382                                    priv->allocation.y2 - priv->allocation.y1);
5383
5384   /* if the actor has a clip set then we have a pretty definite
5385    * size for the paint volume: the actor cannot possibly paint
5386    * outside the clip region.
5387    */
5388   if (priv->clip_to_allocation)
5389     {
5390       /* the allocation has already been set, so we just flip the
5391        * return value
5392        */
5393       res = TRUE;
5394     }
5395   else
5396     {
5397       ClutterActor *child;
5398
5399       if (priv->has_clip &&
5400           priv->clip.width >= 0 &&
5401           priv->clip.height >= 0)
5402         {
5403           ClutterVertex origin;
5404
5405           origin.x = priv->clip.x;
5406           origin.y = priv->clip.y;
5407           origin.z = 0;
5408
5409           clutter_paint_volume_set_origin (volume, &origin);
5410           clutter_paint_volume_set_width (volume, priv->clip.width);
5411           clutter_paint_volume_set_height (volume, priv->clip.height);
5412
5413           res = TRUE;
5414         }
5415
5416       /* if we don't have children we just bail out here... */
5417       if (priv->n_children == 0)
5418         return res;
5419
5420       /* ...but if we have children then we ask for their paint volume in
5421        * our coordinates. if any of our children replies that it doesn't
5422        * have a paint volume, we bail out
5423        */
5424       for (child = priv->first_child;
5425            child != NULL;
5426            child = child->priv->next_sibling)
5427         {
5428           const ClutterPaintVolume *child_volume;
5429
5430           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5431             continue;
5432
5433           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5434           if (child_volume == NULL)
5435             {
5436               res = FALSE;
5437               break;
5438             }
5439
5440           clutter_paint_volume_union (volume, child_volume);
5441           res = TRUE;
5442         }
5443     }
5444
5445   return res;
5446
5447 }
5448
5449 static gboolean
5450 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5451                                      ClutterPaintVolume *volume)
5452 {
5453   ClutterActorClass *klass;
5454   gboolean res;
5455
5456   klass = CLUTTER_ACTOR_GET_CLASS (self);
5457
5458   /* XXX - this thoroughly sucks, but we don't want to penalize users
5459    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5460    * redraw. This should go away in 2.0.
5461    */
5462   if (klass->paint == clutter_actor_real_paint &&
5463       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5464     {
5465       res = TRUE;
5466     }
5467   else
5468     {
5469       /* this is the default return value: we cannot know if a class
5470        * is going to paint outside its allocation, so we take the
5471        * conservative approach.
5472        */
5473       res = FALSE;
5474     }
5475
5476   /* update_default_paint_volume() should only fail if one of the children
5477    * reported an invalid, or no, paint volume
5478    */
5479   if (!clutter_actor_update_default_paint_volume (self, volume))
5480     return FALSE;
5481
5482   return res;
5483 }
5484
5485 /**
5486  * clutter_actor_get_default_paint_volume:
5487  * @self: a #ClutterActor
5488  *
5489  * Retrieves the default paint volume for @self.
5490  *
5491  * This function provides the same #ClutterPaintVolume that would be
5492  * computed by the default implementation inside #ClutterActor of the
5493  * #ClutterActorClass.get_paint_volume() virtual function.
5494  *
5495  * This function should only be used by #ClutterActor subclasses that
5496  * cannot chain up to the parent implementation when computing their
5497  * paint volume.
5498  *
5499  * Return value: (transfer none): a pointer to the default
5500  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5501  *   the actor could not compute a valid paint volume. The returned value
5502  *   is not guaranteed to be stable across multiple frames, so if you
5503  *   want to retain it, you will need to copy it using
5504  *   clutter_paint_volume_copy().
5505  *
5506  * Since: 1.10
5507  */
5508 const ClutterPaintVolume *
5509 clutter_actor_get_default_paint_volume (ClutterActor *self)
5510 {
5511   ClutterPaintVolume volume;
5512   ClutterPaintVolume *res;
5513
5514   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5515
5516   res = NULL;
5517   _clutter_paint_volume_init_static (&volume, self);
5518   if (clutter_actor_update_default_paint_volume (self, &volume))
5519     {
5520       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5521
5522       if (stage != NULL)
5523         {
5524           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5525           _clutter_paint_volume_copy_static (&volume, res);
5526         }
5527     }
5528
5529   clutter_paint_volume_free (&volume);
5530
5531   return res;
5532 }
5533
5534 static gboolean
5535 clutter_actor_real_has_overlaps (ClutterActor *self)
5536 {
5537   /* By default we'll assume that all actors need an offscreen redirect to get
5538    * the correct opacity. Actors such as ClutterTexture that would never need
5539    * an offscreen redirect can override this to return FALSE. */
5540   return TRUE;
5541 }
5542
5543 static void
5544 clutter_actor_real_destroy (ClutterActor *actor)
5545 {
5546   ClutterActorIter iter;
5547
5548   g_object_freeze_notify (G_OBJECT (actor));
5549
5550   clutter_actor_iter_init (&iter, actor);
5551   while (clutter_actor_iter_next (&iter, NULL))
5552     clutter_actor_iter_destroy (&iter);
5553
5554   g_object_thaw_notify (G_OBJECT (actor));
5555 }
5556
5557 static GObject *
5558 clutter_actor_constructor (GType gtype,
5559                            guint n_props,
5560                            GObjectConstructParam *props)
5561 {
5562   GObjectClass *gobject_class;
5563   ClutterActor *self;
5564   GObject *retval;
5565
5566   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5567   retval = gobject_class->constructor (gtype, n_props, props);
5568   self = CLUTTER_ACTOR (retval);
5569
5570   if (self->priv->layout_manager == NULL)
5571     {
5572       ClutterLayoutManager *default_layout;
5573
5574       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5575
5576       default_layout = clutter_fixed_layout_new ();
5577       clutter_actor_set_layout_manager (self, default_layout);
5578     }
5579
5580   return retval;
5581 }
5582
5583 static void
5584 clutter_actor_class_init (ClutterActorClass *klass)
5585 {
5586   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5587
5588   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5589   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5590   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5591   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5592
5593   object_class->constructor = clutter_actor_constructor;
5594   object_class->set_property = clutter_actor_set_property;
5595   object_class->get_property = clutter_actor_get_property;
5596   object_class->dispose = clutter_actor_dispose;
5597   object_class->finalize = clutter_actor_finalize;
5598
5599   klass->show = clutter_actor_real_show;
5600   klass->show_all = clutter_actor_show;
5601   klass->hide = clutter_actor_real_hide;
5602   klass->hide_all = clutter_actor_hide;
5603   klass->map = clutter_actor_real_map;
5604   klass->unmap = clutter_actor_real_unmap;
5605   klass->unrealize = clutter_actor_real_unrealize;
5606   klass->pick = clutter_actor_real_pick;
5607   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5608   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5609   klass->allocate = clutter_actor_real_allocate;
5610   klass->queue_redraw = clutter_actor_real_queue_redraw;
5611   klass->queue_relayout = clutter_actor_real_queue_relayout;
5612   klass->apply_transform = clutter_actor_real_apply_transform;
5613   klass->get_accessible = clutter_actor_real_get_accessible;
5614   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5615   klass->has_overlaps = clutter_actor_real_has_overlaps;
5616   klass->paint = clutter_actor_real_paint;
5617   klass->destroy = clutter_actor_real_destroy;
5618
5619   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5620
5621   /**
5622    * ClutterActor:x:
5623    *
5624    * X coordinate of the actor in pixels. If written, forces a fixed
5625    * position for the actor. If read, returns the fixed position if any,
5626    * otherwise the allocation if available, otherwise 0.
5627    *
5628    * The #ClutterActor:x property is animatable.
5629    */
5630   obj_props[PROP_X] =
5631     g_param_spec_float ("x",
5632                         P_("X coordinate"),
5633                         P_("X coordinate of the actor"),
5634                         -G_MAXFLOAT, G_MAXFLOAT,
5635                         0.0,
5636                         G_PARAM_READWRITE |
5637                         G_PARAM_STATIC_STRINGS |
5638                         CLUTTER_PARAM_ANIMATABLE);
5639
5640   /**
5641    * ClutterActor:y:
5642    *
5643    * Y coordinate of the actor in pixels. If written, forces a fixed
5644    * position for the actor.  If read, returns the fixed position if
5645    * any, otherwise the allocation if available, otherwise 0.
5646    *
5647    * The #ClutterActor:y property is animatable.
5648    */
5649   obj_props[PROP_Y] =
5650     g_param_spec_float ("y",
5651                         P_("Y coordinate"),
5652                         P_("Y coordinate of the actor"),
5653                         -G_MAXFLOAT, G_MAXFLOAT,
5654                         0.0,
5655                         G_PARAM_READWRITE |
5656                         G_PARAM_STATIC_STRINGS |
5657                         CLUTTER_PARAM_ANIMATABLE);
5658
5659   /**
5660    * ClutterActor:position:
5661    *
5662    * The position of the origin of the actor.
5663    *
5664    * This property is a shorthand for setting and getting the
5665    * #ClutterActor:x and #ClutterActor:y properties at the same
5666    * time.
5667    *
5668    * The #ClutterActor:position property is animatable.
5669    *
5670    * Since: 1.12
5671    */
5672   obj_props[PROP_POSITION] =
5673     g_param_spec_boxed ("position",
5674                         P_("Position"),
5675                         P_("The position of the origin of the actor"),
5676                         CLUTTER_TYPE_POINT,
5677                         G_PARAM_READWRITE |
5678                         G_PARAM_STATIC_STRINGS |
5679                         CLUTTER_PARAM_ANIMATABLE);
5680
5681   /**
5682    * ClutterActor:width:
5683    *
5684    * Width of the actor (in pixels). If written, forces the minimum and
5685    * natural size request of the actor to the given width. If read, returns
5686    * the allocated width if available, otherwise the width request.
5687    *
5688    * The #ClutterActor:width property is animatable.
5689    */
5690   obj_props[PROP_WIDTH] =
5691     g_param_spec_float ("width",
5692                         P_("Width"),
5693                         P_("Width of the actor"),
5694                         0.0, G_MAXFLOAT,
5695                         0.0,
5696                         G_PARAM_READWRITE |
5697                         G_PARAM_STATIC_STRINGS |
5698                         CLUTTER_PARAM_ANIMATABLE);
5699
5700   /**
5701    * ClutterActor:height:
5702    *
5703    * Height of the actor (in pixels).  If written, forces the minimum and
5704    * natural size request of the actor to the given height. If read, returns
5705    * the allocated height if available, otherwise the height request.
5706    *
5707    * The #ClutterActor:height property is animatable.
5708    */
5709   obj_props[PROP_HEIGHT] =
5710     g_param_spec_float ("height",
5711                         P_("Height"),
5712                         P_("Height of the actor"),
5713                         0.0, G_MAXFLOAT,
5714                         0.0,
5715                         G_PARAM_READWRITE |
5716                         G_PARAM_STATIC_STRINGS |
5717                         CLUTTER_PARAM_ANIMATABLE);
5718
5719   /**
5720    * ClutterActor:size:
5721    *
5722    * The size of the actor.
5723    *
5724    * This property is a shorthand for setting and getting the
5725    * #ClutterActor:width and #ClutterActor:height at the same time.
5726    *
5727    * The #ClutterActor:size property is animatable.
5728    *
5729    * Since: 1.12
5730    */
5731   obj_props[PROP_SIZE] =
5732     g_param_spec_boxed ("size",
5733                         P_("Size"),
5734                         P_("The size of the actor"),
5735                         CLUTTER_TYPE_SIZE,
5736                         G_PARAM_READWRITE |
5737                         G_PARAM_STATIC_STRINGS |
5738                         CLUTTER_PARAM_ANIMATABLE);
5739
5740   /**
5741    * ClutterActor:fixed-x:
5742    *
5743    * The fixed X position of the actor in pixels.
5744    *
5745    * Writing this property sets #ClutterActor:fixed-position-set
5746    * property as well, as a side effect
5747    *
5748    * Since: 0.8
5749    */
5750   obj_props[PROP_FIXED_X] =
5751     g_param_spec_float ("fixed-x",
5752                         P_("Fixed X"),
5753                         P_("Forced X position of the actor"),
5754                         -G_MAXFLOAT, G_MAXFLOAT,
5755                         0.0,
5756                         CLUTTER_PARAM_READWRITE);
5757
5758   /**
5759    * ClutterActor:fixed-y:
5760    *
5761    * The fixed Y position of the actor in pixels.
5762    *
5763    * Writing this property sets the #ClutterActor:fixed-position-set
5764    * property as well, as a side effect
5765    *
5766    * Since: 0.8
5767    */
5768   obj_props[PROP_FIXED_Y] =
5769     g_param_spec_float ("fixed-y",
5770                         P_("Fixed Y"),
5771                         P_("Forced Y position of the actor"),
5772                         -G_MAXFLOAT, G_MAXFLOAT,
5773                         0,
5774                         CLUTTER_PARAM_READWRITE);
5775
5776   /**
5777    * ClutterActor:fixed-position-set:
5778    *
5779    * This flag controls whether the #ClutterActor:fixed-x and
5780    * #ClutterActor:fixed-y properties are used
5781    *
5782    * Since: 0.8
5783    */
5784   obj_props[PROP_FIXED_POSITION_SET] =
5785     g_param_spec_boolean ("fixed-position-set",
5786                           P_("Fixed position set"),
5787                           P_("Whether to use fixed positioning for the actor"),
5788                           FALSE,
5789                           CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:min-width:
5793    *
5794    * A forced minimum width request for the actor, in pixels
5795    *
5796    * Writing this property sets the #ClutterActor:min-width-set property
5797    * as well, as a side effect.
5798    *
5799    *This property overrides the usual width request of the actor.
5800    *
5801    * Since: 0.8
5802    */
5803   obj_props[PROP_MIN_WIDTH] =
5804     g_param_spec_float ("min-width",
5805                         P_("Min Width"),
5806                         P_("Forced minimum width request for the actor"),
5807                         0.0, G_MAXFLOAT,
5808                         0.0,
5809                         CLUTTER_PARAM_READWRITE);
5810
5811   /**
5812    * ClutterActor:min-height:
5813    *
5814    * A forced minimum height request for the actor, in pixels
5815    *
5816    * Writing this property sets the #ClutterActor:min-height-set property
5817    * as well, as a side effect. This property overrides the usual height
5818    * request of the actor.
5819    *
5820    * Since: 0.8
5821    */
5822   obj_props[PROP_MIN_HEIGHT] =
5823     g_param_spec_float ("min-height",
5824                         P_("Min Height"),
5825                         P_("Forced minimum height request for the actor"),
5826                         0.0, G_MAXFLOAT,
5827                         0.0,
5828                         CLUTTER_PARAM_READWRITE);
5829
5830   /**
5831    * ClutterActor:natural-width:
5832    *
5833    * A forced natural width request for the actor, in pixels
5834    *
5835    * Writing this property sets the #ClutterActor:natural-width-set
5836    * property as well, as a side effect. This property overrides the
5837    * usual width request of the actor
5838    *
5839    * Since: 0.8
5840    */
5841   obj_props[PROP_NATURAL_WIDTH] =
5842     g_param_spec_float ("natural-width",
5843                         P_("Natural Width"),
5844                         P_("Forced natural width request for the actor"),
5845                         0.0, G_MAXFLOAT,
5846                         0.0,
5847                         CLUTTER_PARAM_READWRITE);
5848
5849   /**
5850    * ClutterActor:natural-height:
5851    *
5852    * A forced natural height request for the actor, in pixels
5853    *
5854    * Writing this property sets the #ClutterActor:natural-height-set
5855    * property as well, as a side effect. This property overrides the
5856    * usual height request of the actor
5857    *
5858    * Since: 0.8
5859    */
5860   obj_props[PROP_NATURAL_HEIGHT] =
5861     g_param_spec_float ("natural-height",
5862                         P_("Natural Height"),
5863                         P_("Forced natural height request for the actor"),
5864                         0.0, G_MAXFLOAT,
5865                         0.0,
5866                         CLUTTER_PARAM_READWRITE);
5867
5868   /**
5869    * ClutterActor:min-width-set:
5870    *
5871    * This flag controls whether the #ClutterActor:min-width property
5872    * is used
5873    *
5874    * Since: 0.8
5875    */
5876   obj_props[PROP_MIN_WIDTH_SET] =
5877     g_param_spec_boolean ("min-width-set",
5878                           P_("Minimum width set"),
5879                           P_("Whether to use the min-width property"),
5880                           FALSE,
5881                           CLUTTER_PARAM_READWRITE);
5882
5883   /**
5884    * ClutterActor:min-height-set:
5885    *
5886    * This flag controls whether the #ClutterActor:min-height property
5887    * is used
5888    *
5889    * Since: 0.8
5890    */
5891   obj_props[PROP_MIN_HEIGHT_SET] =
5892     g_param_spec_boolean ("min-height-set",
5893                           P_("Minimum height set"),
5894                           P_("Whether to use the min-height property"),
5895                           FALSE,
5896                           CLUTTER_PARAM_READWRITE);
5897
5898   /**
5899    * ClutterActor:natural-width-set:
5900    *
5901    * This flag controls whether the #ClutterActor:natural-width property
5902    * is used
5903    *
5904    * Since: 0.8
5905    */
5906   obj_props[PROP_NATURAL_WIDTH_SET] =
5907     g_param_spec_boolean ("natural-width-set",
5908                           P_("Natural width set"),
5909                           P_("Whether to use the natural-width property"),
5910                           FALSE,
5911                           CLUTTER_PARAM_READWRITE);
5912
5913   /**
5914    * ClutterActor:natural-height-set:
5915    *
5916    * This flag controls whether the #ClutterActor:natural-height property
5917    * is used
5918    *
5919    * Since: 0.8
5920    */
5921   obj_props[PROP_NATURAL_HEIGHT_SET] =
5922     g_param_spec_boolean ("natural-height-set",
5923                           P_("Natural height set"),
5924                           P_("Whether to use the natural-height property"),
5925                           FALSE,
5926                           CLUTTER_PARAM_READWRITE);
5927
5928   /**
5929    * ClutterActor:allocation:
5930    *
5931    * The allocation for the actor, in pixels
5932    *
5933    * This is property is read-only, but you might monitor it to know when an
5934    * actor moves or resizes
5935    *
5936    * Since: 0.8
5937    */
5938   obj_props[PROP_ALLOCATION] =
5939     g_param_spec_boxed ("allocation",
5940                         P_("Allocation"),
5941                         P_("The actor's allocation"),
5942                         CLUTTER_TYPE_ACTOR_BOX,
5943                         G_PARAM_READABLE |
5944                         G_PARAM_STATIC_STRINGS |
5945                         CLUTTER_PARAM_ANIMATABLE);
5946
5947   /**
5948    * ClutterActor:request-mode:
5949    *
5950    * Request mode for the #ClutterActor. The request mode determines the
5951    * type of geometry management used by the actor, either height for width
5952    * (the default) or width for height.
5953    *
5954    * For actors implementing height for width, the parent container should get
5955    * the preferred width first, and then the preferred height for that width.
5956    *
5957    * For actors implementing width for height, the parent container should get
5958    * the preferred height first, and then the preferred width for that height.
5959    *
5960    * For instance:
5961    *
5962    * |[
5963    *   ClutterRequestMode mode;
5964    *   gfloat natural_width, min_width;
5965    *   gfloat natural_height, min_height;
5966    *
5967    *   mode = clutter_actor_get_request_mode (child);
5968    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5969    *     {
5970    *       clutter_actor_get_preferred_width (child, -1,
5971    *                                          &amp;min_width,
5972    *                                          &amp;natural_width);
5973    *       clutter_actor_get_preferred_height (child, natural_width,
5974    *                                           &amp;min_height,
5975    *                                           &amp;natural_height);
5976    *     }
5977    *   else
5978    *     {
5979    *       clutter_actor_get_preferred_height (child, -1,
5980    *                                           &amp;min_height,
5981    *                                           &amp;natural_height);
5982    *       clutter_actor_get_preferred_width (child, natural_height,
5983    *                                          &amp;min_width,
5984    *                                          &amp;natural_width);
5985    *     }
5986    * ]|
5987    *
5988    * will retrieve the minimum and natural width and height depending on the
5989    * preferred request mode of the #ClutterActor "child".
5990    *
5991    * The clutter_actor_get_preferred_size() function will implement this
5992    * check for you.
5993    *
5994    * Since: 0.8
5995    */
5996   obj_props[PROP_REQUEST_MODE] =
5997     g_param_spec_enum ("request-mode",
5998                        P_("Request Mode"),
5999                        P_("The actor's request mode"),
6000                        CLUTTER_TYPE_REQUEST_MODE,
6001                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
6002                        CLUTTER_PARAM_READWRITE);
6003
6004   /**
6005    * ClutterActor:depth:
6006    *
6007    * The position of the actor on the Z axis.
6008    *
6009    * The #ClutterActor:depth property is relative to the parent's
6010    * modelview matrix.
6011    *
6012    * The #ClutterActor:depth property is animatable.
6013    *
6014    * Since: 0.6
6015    */
6016   obj_props[PROP_DEPTH] =
6017     g_param_spec_float ("depth",
6018                         P_("Depth"),
6019                         P_("Position on the Z axis"),
6020                         -G_MAXFLOAT, G_MAXFLOAT,
6021                         0.0,
6022                         G_PARAM_READWRITE |
6023                         G_PARAM_STATIC_STRINGS |
6024                         CLUTTER_PARAM_ANIMATABLE);
6025
6026   /**
6027    * ClutterActor:opacity:
6028    *
6029    * Opacity of an actor, between 0 (fully transparent) and
6030    * 255 (fully opaque)
6031    *
6032    * The #ClutterActor:opacity property is animatable.
6033    */
6034   obj_props[PROP_OPACITY] =
6035     g_param_spec_uint ("opacity",
6036                        P_("Opacity"),
6037                        P_("Opacity of an actor"),
6038                        0, 255,
6039                        255,
6040                        G_PARAM_READWRITE |
6041                        G_PARAM_STATIC_STRINGS |
6042                        CLUTTER_PARAM_ANIMATABLE);
6043
6044   /**
6045    * ClutterActor:offscreen-redirect:
6046    *
6047    * Determines the conditions in which the actor will be redirected
6048    * to an offscreen framebuffer while being painted. For example this
6049    * can be used to cache an actor in a framebuffer or for improved
6050    * handling of transparent actors. See
6051    * clutter_actor_set_offscreen_redirect() for details.
6052    *
6053    * Since: 1.8
6054    */
6055   obj_props[PROP_OFFSCREEN_REDIRECT] =
6056     g_param_spec_flags ("offscreen-redirect",
6057                         P_("Offscreen redirect"),
6058                         P_("Flags controlling when to flatten the actor into a single image"),
6059                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6060                         0,
6061                         CLUTTER_PARAM_READWRITE);
6062
6063   /**
6064    * ClutterActor:visible:
6065    *
6066    * Whether the actor is set to be visible or not
6067    *
6068    * See also #ClutterActor:mapped
6069    */
6070   obj_props[PROP_VISIBLE] =
6071     g_param_spec_boolean ("visible",
6072                           P_("Visible"),
6073                           P_("Whether the actor is visible or not"),
6074                           FALSE,
6075                           CLUTTER_PARAM_READWRITE);
6076
6077   /**
6078    * ClutterActor:mapped:
6079    *
6080    * Whether the actor is mapped (will be painted when the stage
6081    * to which it belongs is mapped)
6082    *
6083    * Since: 1.0
6084    */
6085   obj_props[PROP_MAPPED] =
6086     g_param_spec_boolean ("mapped",
6087                           P_("Mapped"),
6088                           P_("Whether the actor will be painted"),
6089                           FALSE,
6090                           CLUTTER_PARAM_READABLE);
6091
6092   /**
6093    * ClutterActor:realized:
6094    *
6095    * Whether the actor has been realized
6096    *
6097    * Since: 1.0
6098    */
6099   obj_props[PROP_REALIZED] =
6100     g_param_spec_boolean ("realized",
6101                           P_("Realized"),
6102                           P_("Whether the actor has been realized"),
6103                           FALSE,
6104                           CLUTTER_PARAM_READABLE);
6105
6106   /**
6107    * ClutterActor:reactive:
6108    *
6109    * Whether the actor is reactive to events or not
6110    *
6111    * Only reactive actors will emit event-related signals
6112    *
6113    * Since: 0.6
6114    */
6115   obj_props[PROP_REACTIVE] =
6116     g_param_spec_boolean ("reactive",
6117                           P_("Reactive"),
6118                           P_("Whether the actor is reactive to events"),
6119                           FALSE,
6120                           CLUTTER_PARAM_READWRITE);
6121
6122   /**
6123    * ClutterActor:has-clip:
6124    *
6125    * Whether the actor has the #ClutterActor:clip property set or not
6126    */
6127   obj_props[PROP_HAS_CLIP] =
6128     g_param_spec_boolean ("has-clip",
6129                           P_("Has Clip"),
6130                           P_("Whether the actor has a clip set"),
6131                           FALSE,
6132                           CLUTTER_PARAM_READABLE);
6133
6134   /**
6135    * ClutterActor:clip:
6136    *
6137    * The clip region for the actor, in actor-relative coordinates
6138    *
6139    * Every part of the actor outside the clip region will not be
6140    * painted
6141    */
6142   obj_props[PROP_CLIP] =
6143     g_param_spec_boxed ("clip",
6144                         P_("Clip"),
6145                         P_("The clip region for the actor"),
6146                         CLUTTER_TYPE_GEOMETRY,
6147                         CLUTTER_PARAM_READWRITE);
6148
6149   /**
6150    * ClutterActor:name:
6151    *
6152    * The name of the actor
6153    *
6154    * Since: 0.2
6155    */
6156   obj_props[PROP_NAME] =
6157     g_param_spec_string ("name",
6158                          P_("Name"),
6159                          P_("Name of the actor"),
6160                          NULL,
6161                          CLUTTER_PARAM_READWRITE);
6162
6163   /**
6164    * ClutterActor:scale-x:
6165    *
6166    * The horizontal scale of the actor.
6167    *
6168    * The #ClutterActor:scale-x property is animatable.
6169    *
6170    * Since: 0.6
6171    */
6172   obj_props[PROP_SCALE_X] =
6173     g_param_spec_double ("scale-x",
6174                          P_("Scale X"),
6175                          P_("Scale factor on the X axis"),
6176                          0.0, G_MAXDOUBLE,
6177                          1.0,
6178                          G_PARAM_READWRITE |
6179                          G_PARAM_STATIC_STRINGS |
6180                          CLUTTER_PARAM_ANIMATABLE);
6181
6182   /**
6183    * ClutterActor:scale-y:
6184    *
6185    * The vertical scale of the actor.
6186    *
6187    * The #ClutterActor:scale-y property is animatable.
6188    *
6189    * Since: 0.6
6190    */
6191   obj_props[PROP_SCALE_Y] =
6192     g_param_spec_double ("scale-y",
6193                          P_("Scale Y"),
6194                          P_("Scale factor on the Y axis"),
6195                          0.0, G_MAXDOUBLE,
6196                          1.0,
6197                          G_PARAM_READWRITE |
6198                          G_PARAM_STATIC_STRINGS |
6199                          CLUTTER_PARAM_ANIMATABLE);
6200
6201   /**
6202    * ClutterActor:scale-center-x:
6203    *
6204    * The horizontal center point for scaling
6205    *
6206    * Since: 1.0
6207    */
6208   obj_props[PROP_SCALE_CENTER_X] =
6209     g_param_spec_float ("scale-center-x",
6210                         P_("Scale Center X"),
6211                         P_("Horizontal scale center"),
6212                         -G_MAXFLOAT, G_MAXFLOAT,
6213                         0.0,
6214                         CLUTTER_PARAM_READWRITE);
6215
6216   /**
6217    * ClutterActor:scale-center-y:
6218    *
6219    * The vertical center point for scaling
6220    *
6221    * Since: 1.0
6222    */
6223   obj_props[PROP_SCALE_CENTER_Y] =
6224     g_param_spec_float ("scale-center-y",
6225                         P_("Scale Center Y"),
6226                         P_("Vertical scale center"),
6227                         -G_MAXFLOAT, G_MAXFLOAT,
6228                         0.0,
6229                         CLUTTER_PARAM_READWRITE);
6230
6231   /**
6232    * ClutterActor:scale-gravity:
6233    *
6234    * The center point for scaling expressed as a #ClutterGravity
6235    *
6236    * Since: 1.0
6237    */
6238   obj_props[PROP_SCALE_GRAVITY] =
6239     g_param_spec_enum ("scale-gravity",
6240                        P_("Scale Gravity"),
6241                        P_("The center of scaling"),
6242                        CLUTTER_TYPE_GRAVITY,
6243                        CLUTTER_GRAVITY_NONE,
6244                        CLUTTER_PARAM_READWRITE);
6245
6246   /**
6247    * ClutterActor:rotation-angle-x:
6248    *
6249    * The rotation angle on the X axis.
6250    *
6251    * The #ClutterActor:rotation-angle-x property is animatable.
6252    *
6253    * Since: 0.6
6254    */
6255   obj_props[PROP_ROTATION_ANGLE_X] =
6256     g_param_spec_double ("rotation-angle-x",
6257                          P_("Rotation Angle X"),
6258                          P_("The rotation angle on the X axis"),
6259                          -G_MAXDOUBLE, G_MAXDOUBLE,
6260                          0.0,
6261                          G_PARAM_READWRITE |
6262                          G_PARAM_STATIC_STRINGS |
6263                          CLUTTER_PARAM_ANIMATABLE);
6264
6265   /**
6266    * ClutterActor:rotation-angle-y:
6267    *
6268    * The rotation angle on the Y axis
6269    *
6270    * The #ClutterActor:rotation-angle-y property is animatable.
6271    *
6272    * Since: 0.6
6273    */
6274   obj_props[PROP_ROTATION_ANGLE_Y] =
6275     g_param_spec_double ("rotation-angle-y",
6276                          P_("Rotation Angle Y"),
6277                          P_("The rotation angle on the Y axis"),
6278                          -G_MAXDOUBLE, G_MAXDOUBLE,
6279                          0.0,
6280                          G_PARAM_READWRITE |
6281                          G_PARAM_STATIC_STRINGS |
6282                          CLUTTER_PARAM_ANIMATABLE);
6283
6284   /**
6285    * ClutterActor:rotation-angle-z:
6286    *
6287    * The rotation angle on the Z axis
6288    *
6289    * The #ClutterActor:rotation-angle-z property is animatable.
6290    *
6291    * Since: 0.6
6292    */
6293   obj_props[PROP_ROTATION_ANGLE_Z] =
6294     g_param_spec_double ("rotation-angle-z",
6295                          P_("Rotation Angle Z"),
6296                          P_("The rotation angle on the Z axis"),
6297                          -G_MAXDOUBLE, G_MAXDOUBLE,
6298                          0.0,
6299                          G_PARAM_READWRITE |
6300                          G_PARAM_STATIC_STRINGS |
6301                          CLUTTER_PARAM_ANIMATABLE);
6302
6303   /**
6304    * ClutterActor:rotation-center-x:
6305    *
6306    * The rotation center on the X axis.
6307    *
6308    * Since: 0.6
6309    */
6310   obj_props[PROP_ROTATION_CENTER_X] =
6311     g_param_spec_boxed ("rotation-center-x",
6312                         P_("Rotation Center X"),
6313                         P_("The rotation center on the X axis"),
6314                         CLUTTER_TYPE_VERTEX,
6315                         CLUTTER_PARAM_READWRITE);
6316
6317   /**
6318    * ClutterActor:rotation-center-y:
6319    *
6320    * The rotation center on the Y axis.
6321    *
6322    * Since: 0.6
6323    */
6324   obj_props[PROP_ROTATION_CENTER_Y] =
6325     g_param_spec_boxed ("rotation-center-y",
6326                         P_("Rotation Center Y"),
6327                         P_("The rotation center on the Y axis"),
6328                         CLUTTER_TYPE_VERTEX,
6329                         CLUTTER_PARAM_READWRITE);
6330
6331   /**
6332    * ClutterActor:rotation-center-z:
6333    *
6334    * The rotation center on the Z axis.
6335    *
6336    * Since: 0.6
6337    */
6338   obj_props[PROP_ROTATION_CENTER_Z] =
6339     g_param_spec_boxed ("rotation-center-z",
6340                         P_("Rotation Center Z"),
6341                         P_("The rotation center on the Z axis"),
6342                         CLUTTER_TYPE_VERTEX,
6343                         CLUTTER_PARAM_READWRITE);
6344
6345   /**
6346    * ClutterActor:rotation-center-z-gravity:
6347    *
6348    * The rotation center on the Z axis expressed as a #ClutterGravity.
6349    *
6350    * Since: 1.0
6351    */
6352   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6353     g_param_spec_enum ("rotation-center-z-gravity",
6354                        P_("Rotation Center Z Gravity"),
6355                        P_("Center point for rotation around the Z axis"),
6356                        CLUTTER_TYPE_GRAVITY,
6357                        CLUTTER_GRAVITY_NONE,
6358                        CLUTTER_PARAM_READWRITE);
6359
6360   /**
6361    * ClutterActor:anchor-x:
6362    *
6363    * The X coordinate of an actor's anchor point, relative to
6364    * the actor coordinate space, in pixels
6365    *
6366    * Since: 0.8
6367    */
6368   obj_props[PROP_ANCHOR_X] =
6369     g_param_spec_float ("anchor-x",
6370                         P_("Anchor X"),
6371                         P_("X coordinate of the anchor point"),
6372                         -G_MAXFLOAT, G_MAXFLOAT,
6373                         0,
6374                         CLUTTER_PARAM_READWRITE);
6375
6376   /**
6377    * ClutterActor:anchor-y:
6378    *
6379    * The Y coordinate of an actor's anchor point, relative to
6380    * the actor coordinate space, in pixels
6381    *
6382    * Since: 0.8
6383    */
6384   obj_props[PROP_ANCHOR_Y] =
6385     g_param_spec_float ("anchor-y",
6386                         P_("Anchor Y"),
6387                         P_("Y coordinate of the anchor point"),
6388                         -G_MAXFLOAT, G_MAXFLOAT,
6389                         0,
6390                         CLUTTER_PARAM_READWRITE);
6391
6392   /**
6393    * ClutterActor:anchor-gravity:
6394    *
6395    * The anchor point expressed as a #ClutterGravity
6396    *
6397    * Since: 1.0
6398    */
6399   obj_props[PROP_ANCHOR_GRAVITY] =
6400     g_param_spec_enum ("anchor-gravity",
6401                        P_("Anchor Gravity"),
6402                        P_("The anchor point as a ClutterGravity"),
6403                        CLUTTER_TYPE_GRAVITY,
6404                        CLUTTER_GRAVITY_NONE,
6405                        CLUTTER_PARAM_READWRITE);
6406
6407   /**
6408    * ClutterActor:show-on-set-parent:
6409    *
6410    * If %TRUE, the actor is automatically shown when parented.
6411    *
6412    * Calling clutter_actor_hide() on an actor which has not been
6413    * parented will set this property to %FALSE as a side effect.
6414    *
6415    * Since: 0.8
6416    */
6417   obj_props[PROP_SHOW_ON_SET_PARENT] =
6418     g_param_spec_boolean ("show-on-set-parent",
6419                           P_("Show on set parent"),
6420                           P_("Whether the actor is shown when parented"),
6421                           TRUE,
6422                           CLUTTER_PARAM_READWRITE);
6423
6424   /**
6425    * ClutterActor:clip-to-allocation:
6426    *
6427    * Whether the clip region should track the allocated area
6428    * of the actor.
6429    *
6430    * This property is ignored if a clip area has been explicitly
6431    * set using clutter_actor_set_clip().
6432    *
6433    * Since: 1.0
6434    */
6435   obj_props[PROP_CLIP_TO_ALLOCATION] =
6436     g_param_spec_boolean ("clip-to-allocation",
6437                           P_("Clip to Allocation"),
6438                           P_("Sets the clip region to track the actor's allocation"),
6439                           FALSE,
6440                           CLUTTER_PARAM_READWRITE);
6441
6442   /**
6443    * ClutterActor:text-direction:
6444    *
6445    * The direction of the text inside a #ClutterActor.
6446    *
6447    * Since: 1.0
6448    */
6449   obj_props[PROP_TEXT_DIRECTION] =
6450     g_param_spec_enum ("text-direction",
6451                        P_("Text Direction"),
6452                        P_("Direction of the text"),
6453                        CLUTTER_TYPE_TEXT_DIRECTION,
6454                        CLUTTER_TEXT_DIRECTION_LTR,
6455                        CLUTTER_PARAM_READWRITE);
6456
6457   /**
6458    * ClutterActor:has-pointer:
6459    *
6460    * Whether the actor contains the pointer of a #ClutterInputDevice
6461    * or not.
6462    *
6463    * Since: 1.2
6464    */
6465   obj_props[PROP_HAS_POINTER] =
6466     g_param_spec_boolean ("has-pointer",
6467                           P_("Has Pointer"),
6468                           P_("Whether the actor contains the pointer of an input device"),
6469                           FALSE,
6470                           CLUTTER_PARAM_READABLE);
6471
6472   /**
6473    * ClutterActor:actions:
6474    *
6475    * Adds a #ClutterAction to the actor
6476    *
6477    * Since: 1.4
6478    */
6479   obj_props[PROP_ACTIONS] =
6480     g_param_spec_object ("actions",
6481                          P_("Actions"),
6482                          P_("Adds an action to the actor"),
6483                          CLUTTER_TYPE_ACTION,
6484                          CLUTTER_PARAM_WRITABLE);
6485
6486   /**
6487    * ClutterActor:constraints:
6488    *
6489    * Adds a #ClutterConstraint to the actor
6490    *
6491    * Since: 1.4
6492    */
6493   obj_props[PROP_CONSTRAINTS] =
6494     g_param_spec_object ("constraints",
6495                          P_("Constraints"),
6496                          P_("Adds a constraint to the actor"),
6497                          CLUTTER_TYPE_CONSTRAINT,
6498                          CLUTTER_PARAM_WRITABLE);
6499
6500   /**
6501    * ClutterActor:effect:
6502    *
6503    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6504    *
6505    * Since: 1.4
6506    */
6507   obj_props[PROP_EFFECT] =
6508     g_param_spec_object ("effect",
6509                          P_("Effect"),
6510                          P_("Add an effect to be applied on the actor"),
6511                          CLUTTER_TYPE_EFFECT,
6512                          CLUTTER_PARAM_WRITABLE);
6513
6514   /**
6515    * ClutterActor:layout-manager:
6516    *
6517    * A delegate object for controlling the layout of the children of
6518    * an actor.
6519    *
6520    * Since: 1.10
6521    */
6522   obj_props[PROP_LAYOUT_MANAGER] =
6523     g_param_spec_object ("layout-manager",
6524                          P_("Layout Manager"),
6525                          P_("The object controlling the layout of an actor's children"),
6526                          CLUTTER_TYPE_LAYOUT_MANAGER,
6527                          CLUTTER_PARAM_READWRITE);
6528
6529   /**
6530    * ClutterActor:x-expand:
6531    *
6532    * Whether a layout manager should assign more space to the actor on
6533    * the X axis.
6534    *
6535    * Since: 1.12
6536    */
6537   obj_props[PROP_X_EXPAND] =
6538     g_param_spec_boolean ("x-expand",
6539                           P_("X Expand"),
6540                           P_("Whether extra horizontal space should be assigned to the actor"),
6541                           FALSE,
6542                           G_PARAM_READWRITE |
6543                           G_PARAM_STATIC_STRINGS);
6544
6545   /**
6546    * ClutterActor:y-expand:
6547    *
6548    * Whether a layout manager should assign more space to the actor on
6549    * the Y axis.
6550    *
6551    * Since: 1.12
6552    */
6553   obj_props[PROP_Y_EXPAND] =
6554     g_param_spec_boolean ("y-expand",
6555                           P_("Y Expand"),
6556                           P_("Whether extra vertical space should be assigned to the actor"),
6557                           FALSE,
6558                           G_PARAM_READWRITE |
6559                           G_PARAM_STATIC_STRINGS);
6560
6561   /**
6562    * ClutterActor:x-align:
6563    *
6564    * The alignment of an actor on the X axis, if the actor has been given
6565    * extra space for its allocation. See also the #ClutterActor:x-expand
6566    * property.
6567    *
6568    * Since: 1.10
6569    */
6570   obj_props[PROP_X_ALIGN] =
6571     g_param_spec_enum ("x-align",
6572                        P_("X Alignment"),
6573                        P_("The alignment of the actor on the X axis within its allocation"),
6574                        CLUTTER_TYPE_ACTOR_ALIGN,
6575                        CLUTTER_ACTOR_ALIGN_FILL,
6576                        CLUTTER_PARAM_READWRITE);
6577
6578   /**
6579    * ClutterActor:y-align:
6580    *
6581    * The alignment of an actor on the Y axis, if the actor has been given
6582    * extra space for its allocation.
6583    *
6584    * Since: 1.10
6585    */
6586   obj_props[PROP_Y_ALIGN] =
6587     g_param_spec_enum ("y-align",
6588                        P_("Y Alignment"),
6589                        P_("The alignment of the actor on the Y axis within its allocation"),
6590                        CLUTTER_TYPE_ACTOR_ALIGN,
6591                        CLUTTER_ACTOR_ALIGN_FILL,
6592                        CLUTTER_PARAM_READWRITE);
6593
6594   /**
6595    * ClutterActor:margin-top:
6596    *
6597    * The margin (in pixels) from the top of the actor.
6598    *
6599    * This property adds a margin to the actor's preferred size; the margin
6600    * will be automatically taken into account when allocating the actor.
6601    *
6602    * Since: 1.10
6603    */
6604   obj_props[PROP_MARGIN_TOP] =
6605     g_param_spec_float ("margin-top",
6606                         P_("Margin Top"),
6607                         P_("Extra space at the top"),
6608                         0.0, G_MAXFLOAT,
6609                         0.0,
6610                         CLUTTER_PARAM_READWRITE);
6611
6612   /**
6613    * ClutterActor:margin-bottom:
6614    *
6615    * The margin (in pixels) from the bottom of the actor.
6616    *
6617    * This property adds a margin to the actor's preferred size; the margin
6618    * will be automatically taken into account when allocating the actor.
6619    *
6620    * Since: 1.10
6621    */
6622   obj_props[PROP_MARGIN_BOTTOM] =
6623     g_param_spec_float ("margin-bottom",
6624                         P_("Margin Bottom"),
6625                         P_("Extra space at the bottom"),
6626                         0.0, G_MAXFLOAT,
6627                         0.0,
6628                         CLUTTER_PARAM_READWRITE);
6629
6630   /**
6631    * ClutterActor:margin-left:
6632    *
6633    * The margin (in pixels) from the left of the actor.
6634    *
6635    * This property adds a margin to the actor's preferred size; the margin
6636    * will be automatically taken into account when allocating the actor.
6637    *
6638    * Since: 1.10
6639    */
6640   obj_props[PROP_MARGIN_LEFT] =
6641     g_param_spec_float ("margin-left",
6642                         P_("Margin Left"),
6643                         P_("Extra space at the left"),
6644                         0.0, G_MAXFLOAT,
6645                         0.0,
6646                         CLUTTER_PARAM_READWRITE);
6647
6648   /**
6649    * ClutterActor:margin-right:
6650    *
6651    * The margin (in pixels) from the right of the actor.
6652    *
6653    * This property adds a margin to the actor's preferred size; the margin
6654    * will be automatically taken into account when allocating the actor.
6655    *
6656    * Since: 1.10
6657    */
6658   obj_props[PROP_MARGIN_RIGHT] =
6659     g_param_spec_float ("margin-right",
6660                         P_("Margin Right"),
6661                         P_("Extra space at the right"),
6662                         0.0, G_MAXFLOAT,
6663                         0.0,
6664                         CLUTTER_PARAM_READWRITE);
6665
6666   /**
6667    * ClutterActor:background-color-set:
6668    *
6669    * Whether the #ClutterActor:background-color property has been set.
6670    *
6671    * Since: 1.10
6672    */
6673   obj_props[PROP_BACKGROUND_COLOR_SET] =
6674     g_param_spec_boolean ("background-color-set",
6675                           P_("Background Color Set"),
6676                           P_("Whether the background color is set"),
6677                           FALSE,
6678                           CLUTTER_PARAM_READABLE);
6679
6680   /**
6681    * ClutterActor:background-color:
6682    *
6683    * Paints a solid fill of the actor's allocation using the specified
6684    * color.
6685    *
6686    * The #ClutterActor:background-color property is animatable.
6687    *
6688    * Since: 1.10
6689    */
6690   obj_props[PROP_BACKGROUND_COLOR] =
6691     clutter_param_spec_color ("background-color",
6692                               P_("Background color"),
6693                               P_("The actor's background color"),
6694                               CLUTTER_COLOR_Transparent,
6695                               G_PARAM_READWRITE |
6696                               G_PARAM_STATIC_STRINGS |
6697                               CLUTTER_PARAM_ANIMATABLE);
6698
6699   /**
6700    * ClutterActor:first-child:
6701    *
6702    * The actor's first child.
6703    *
6704    * Since: 1.10
6705    */
6706   obj_props[PROP_FIRST_CHILD] =
6707     g_param_spec_object ("first-child",
6708                          P_("First Child"),
6709                          P_("The actor's first child"),
6710                          CLUTTER_TYPE_ACTOR,
6711                          CLUTTER_PARAM_READABLE);
6712
6713   /**
6714    * ClutterActor:last-child:
6715    *
6716    * The actor's last child.
6717    *
6718    * Since: 1.10
6719    */
6720   obj_props[PROP_LAST_CHILD] =
6721     g_param_spec_object ("last-child",
6722                          P_("Last Child"),
6723                          P_("The actor's last child"),
6724                          CLUTTER_TYPE_ACTOR,
6725                          CLUTTER_PARAM_READABLE);
6726
6727   /**
6728    * ClutterActor:content:
6729    *
6730    * The #ClutterContent implementation that controls the content
6731    * of the actor.
6732    *
6733    * Since: 1.10
6734    */
6735   obj_props[PROP_CONTENT] =
6736     g_param_spec_object ("content",
6737                          P_("Content"),
6738                          P_("Delegate object for painting the actor's content"),
6739                          CLUTTER_TYPE_CONTENT,
6740                          CLUTTER_PARAM_READWRITE);
6741
6742   /**
6743    * ClutterActor:content-gravity:
6744    *
6745    * The alignment that should be honoured by the #ClutterContent
6746    * set with the #ClutterActor:content property.
6747    *
6748    * Changing the value of this property will change the bounding box of
6749    * the content; you can use the #ClutterActor:content-box property to
6750    * get the position and size of the content within the actor's
6751    * allocation.
6752    *
6753    * This property is meaningful only for #ClutterContent implementations
6754    * that have a preferred size, and if the preferred size is smaller than
6755    * the actor's allocation.
6756    *
6757    * The #ClutterActor:content-gravity property is animatable.
6758    *
6759    * Since: 1.10
6760    */
6761   obj_props[PROP_CONTENT_GRAVITY] =
6762     g_param_spec_enum ("content-gravity",
6763                        P_("Content Gravity"),
6764                        P_("Alignment of the actor's content"),
6765                        CLUTTER_TYPE_CONTENT_GRAVITY,
6766                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6767                        CLUTTER_PARAM_READWRITE);
6768
6769   /**
6770    * ClutterActor:content-box:
6771    *
6772    * The bounding box for the #ClutterContent used by the actor.
6773    *
6774    * The value of this property is controlled by the #ClutterActor:allocation
6775    * and #ClutterActor:content-gravity properties of #ClutterActor.
6776    *
6777    * The bounding box for the content is guaranteed to never exceed the
6778    * allocation's of the actor.
6779    *
6780    * Since: 1.10
6781    */
6782   obj_props[PROP_CONTENT_BOX] =
6783     g_param_spec_boxed ("content-box",
6784                         P_("Content Box"),
6785                         P_("The bounding box of the actor's content"),
6786                         CLUTTER_TYPE_ACTOR_BOX,
6787                         G_PARAM_READABLE |
6788                         G_PARAM_STATIC_STRINGS |
6789                         CLUTTER_PARAM_ANIMATABLE);
6790
6791   obj_props[PROP_MINIFICATION_FILTER] =
6792     g_param_spec_enum ("minification-filter",
6793                        P_("Minification Filter"),
6794                        P_("The filter used when reducing the size of the content"),
6795                        CLUTTER_TYPE_SCALING_FILTER,
6796                        CLUTTER_SCALING_FILTER_LINEAR,
6797                        CLUTTER_PARAM_READWRITE);
6798
6799   obj_props[PROP_MAGNIFICATION_FILTER] =
6800     g_param_spec_enum ("magnification-filter",
6801                        P_("Magnification Filter"),
6802                        P_("The filter used when increasing the size of the content"),
6803                        CLUTTER_TYPE_SCALING_FILTER,
6804                        CLUTTER_SCALING_FILTER_LINEAR,
6805                        CLUTTER_PARAM_READWRITE);
6806
6807   /**
6808    * ClutterActor:content-repeat:
6809    *
6810    * The repeat policy for the actor's #ClutterActor:content.
6811    *
6812    * Since: 1.12
6813    */
6814   obj_props[PROP_CONTENT_REPEAT] =
6815     g_param_spec_flags ("content-repeat",
6816                         P_("Content Repeat"),
6817                         P_("The repeat policy for the actor's content"),
6818                         CLUTTER_TYPE_CONTENT_REPEAT,
6819                         CLUTTER_REPEAT_NONE,
6820                         G_PARAM_READWRITE |
6821                         G_PARAM_STATIC_STRINGS);
6822
6823   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6824
6825   /**
6826    * ClutterActor::destroy:
6827    * @actor: the #ClutterActor which emitted the signal
6828    *
6829    * The ::destroy signal notifies that all references held on the
6830    * actor which emitted it should be released.
6831    *
6832    * The ::destroy signal should be used by all holders of a reference
6833    * on @actor.
6834    *
6835    * This signal might result in the finalization of the #ClutterActor
6836    * if all references are released.
6837    *
6838    * Composite actors and actors implementing the #ClutterContainer
6839    * interface should override the default implementation of the
6840    * class handler of this signal and call clutter_actor_destroy() on
6841    * their children. When overriding the default class handler, it is
6842    * required to chain up to the parent's implementation.
6843    *
6844    * Since: 0.2
6845    */
6846   actor_signals[DESTROY] =
6847     g_signal_new (I_("destroy"),
6848                   G_TYPE_FROM_CLASS (object_class),
6849                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6850                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6851                   NULL, NULL,
6852                   _clutter_marshal_VOID__VOID,
6853                   G_TYPE_NONE, 0);
6854   /**
6855    * ClutterActor::show:
6856    * @actor: the object which received the signal
6857    *
6858    * The ::show signal is emitted when an actor is visible and
6859    * rendered on the stage.
6860    *
6861    * Since: 0.2
6862    */
6863   actor_signals[SHOW] =
6864     g_signal_new (I_("show"),
6865                   G_TYPE_FROM_CLASS (object_class),
6866                   G_SIGNAL_RUN_FIRST,
6867                   G_STRUCT_OFFSET (ClutterActorClass, show),
6868                   NULL, NULL,
6869                   _clutter_marshal_VOID__VOID,
6870                   G_TYPE_NONE, 0);
6871   /**
6872    * ClutterActor::hide:
6873    * @actor: the object which received the signal
6874    *
6875    * The ::hide signal is emitted when an actor is no longer rendered
6876    * on the stage.
6877    *
6878    * Since: 0.2
6879    */
6880   actor_signals[HIDE] =
6881     g_signal_new (I_("hide"),
6882                   G_TYPE_FROM_CLASS (object_class),
6883                   G_SIGNAL_RUN_FIRST,
6884                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6885                   NULL, NULL,
6886                   _clutter_marshal_VOID__VOID,
6887                   G_TYPE_NONE, 0);
6888   /**
6889    * ClutterActor::parent-set:
6890    * @actor: the object which received the signal
6891    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6892    *
6893    * This signal is emitted when the parent of the actor changes.
6894    *
6895    * Since: 0.2
6896    */
6897   actor_signals[PARENT_SET] =
6898     g_signal_new (I_("parent-set"),
6899                   G_TYPE_FROM_CLASS (object_class),
6900                   G_SIGNAL_RUN_LAST,
6901                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6902                   NULL, NULL,
6903                   _clutter_marshal_VOID__OBJECT,
6904                   G_TYPE_NONE, 1,
6905                   CLUTTER_TYPE_ACTOR);
6906
6907   /**
6908    * ClutterActor::queue-redraw:
6909    * @actor: the actor we're bubbling the redraw request through
6910    * @origin: the actor which initiated the redraw request
6911    *
6912    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6913    * is called on @origin.
6914    *
6915    * The default implementation for #ClutterActor chains up to the
6916    * parent actor and queues a redraw on the parent, thus "bubbling"
6917    * the redraw queue up through the actor graph. The default
6918    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6919    * in a main loop idle handler.
6920    *
6921    * Note that the @origin actor may be the stage, or a container; it
6922    * does not have to be a leaf node in the actor graph.
6923    *
6924    * Toolkits embedding a #ClutterStage which require a redraw and
6925    * relayout cycle can stop the emission of this signal using the
6926    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6927    * themselves, like:
6928    *
6929    * |[
6930    *   static void
6931    *   on_redraw_complete (gpointer data)
6932    *   {
6933    *     ClutterStage *stage = data;
6934    *
6935    *     /&ast; execute the Clutter drawing pipeline &ast;/
6936    *     clutter_stage_ensure_redraw (stage);
6937    *   }
6938    *
6939    *   static void
6940    *   on_stage_queue_redraw (ClutterStage *stage)
6941    *   {
6942    *     /&ast; this prevents the default handler to run &ast;/
6943    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6944    *
6945    *     /&ast; queue a redraw with the host toolkit and call
6946    *      &ast; a function when the redraw has been completed
6947    *      &ast;/
6948    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6949    *   }
6950    * ]|
6951    *
6952    * <note><para>This signal is emitted before the Clutter paint
6953    * pipeline is executed. If you want to know when the pipeline has
6954    * been completed you should connect to the ::paint signal on the
6955    * Stage with g_signal_connect_after().</para></note>
6956    *
6957    * Since: 1.0
6958    */
6959   actor_signals[QUEUE_REDRAW] =
6960     g_signal_new (I_("queue-redraw"),
6961                   G_TYPE_FROM_CLASS (object_class),
6962                   G_SIGNAL_RUN_LAST |
6963                   G_SIGNAL_NO_HOOKS,
6964                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6965                   NULL, NULL,
6966                   _clutter_marshal_VOID__OBJECT,
6967                   G_TYPE_NONE, 1,
6968                   CLUTTER_TYPE_ACTOR);
6969
6970   /**
6971    * ClutterActor::queue-relayout:
6972    * @actor: the actor being queued for relayout
6973    *
6974    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6975    * is called on an actor.
6976    *
6977    * The default implementation for #ClutterActor chains up to the
6978    * parent actor and queues a relayout on the parent, thus "bubbling"
6979    * the relayout queue up through the actor graph.
6980    *
6981    * The main purpose of this signal is to allow relayout to be propagated
6982    * properly in the procense of #ClutterClone actors. Applications will
6983    * not normally need to connect to this signal.
6984    *
6985    * Since: 1.2
6986    */
6987   actor_signals[QUEUE_RELAYOUT] =
6988     g_signal_new (I_("queue-relayout"),
6989                   G_TYPE_FROM_CLASS (object_class),
6990                   G_SIGNAL_RUN_LAST |
6991                   G_SIGNAL_NO_HOOKS,
6992                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6993                   NULL, NULL,
6994                   _clutter_marshal_VOID__VOID,
6995                   G_TYPE_NONE, 0);
6996
6997   /**
6998    * ClutterActor::event:
6999    * @actor: the actor which received the event
7000    * @event: a #ClutterEvent
7001    *
7002    * The ::event signal is emitted each time an event is received
7003    * by the @actor. This signal will be emitted on every actor,
7004    * following the hierarchy chain, until it reaches the top-level
7005    * container (the #ClutterStage).
7006    *
7007    * Return value: %TRUE if the event has been handled by the actor,
7008    *   or %FALSE to continue the emission.
7009    *
7010    * Since: 0.6
7011    */
7012   actor_signals[EVENT] =
7013     g_signal_new (I_("event"),
7014                   G_TYPE_FROM_CLASS (object_class),
7015                   G_SIGNAL_RUN_LAST,
7016                   G_STRUCT_OFFSET (ClutterActorClass, event),
7017                   _clutter_boolean_handled_accumulator, NULL,
7018                   _clutter_marshal_BOOLEAN__BOXED,
7019                   G_TYPE_BOOLEAN, 1,
7020                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7021   /**
7022    * ClutterActor::button-press-event:
7023    * @actor: the actor which received the event
7024    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7025    *
7026    * The ::button-press-event signal is emitted each time a mouse button
7027    * is pressed on @actor.
7028    *
7029    * Return value: %TRUE if the event has been handled by the actor,
7030    *   or %FALSE to continue the emission.
7031    *
7032    * Since: 0.6
7033    */
7034   actor_signals[BUTTON_PRESS_EVENT] =
7035     g_signal_new (I_("button-press-event"),
7036                   G_TYPE_FROM_CLASS (object_class),
7037                   G_SIGNAL_RUN_LAST,
7038                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7039                   _clutter_boolean_handled_accumulator, NULL,
7040                   _clutter_marshal_BOOLEAN__BOXED,
7041                   G_TYPE_BOOLEAN, 1,
7042                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7043   /**
7044    * ClutterActor::button-release-event:
7045    * @actor: the actor which received the event
7046    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7047    *
7048    * The ::button-release-event signal is emitted each time a mouse button
7049    * is released on @actor.
7050    *
7051    * Return value: %TRUE if the event has been handled by the actor,
7052    *   or %FALSE to continue the emission.
7053    *
7054    * Since: 0.6
7055    */
7056   actor_signals[BUTTON_RELEASE_EVENT] =
7057     g_signal_new (I_("button-release-event"),
7058                   G_TYPE_FROM_CLASS (object_class),
7059                   G_SIGNAL_RUN_LAST,
7060                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7061                   _clutter_boolean_handled_accumulator, NULL,
7062                   _clutter_marshal_BOOLEAN__BOXED,
7063                   G_TYPE_BOOLEAN, 1,
7064                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7065   /**
7066    * ClutterActor::scroll-event:
7067    * @actor: the actor which received the event
7068    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7069    *
7070    * The ::scroll-event signal is emitted each time the mouse is
7071    * scrolled on @actor
7072    *
7073    * Return value: %TRUE if the event has been handled by the actor,
7074    *   or %FALSE to continue the emission.
7075    *
7076    * Since: 0.6
7077    */
7078   actor_signals[SCROLL_EVENT] =
7079     g_signal_new (I_("scroll-event"),
7080                   G_TYPE_FROM_CLASS (object_class),
7081                   G_SIGNAL_RUN_LAST,
7082                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7083                   _clutter_boolean_handled_accumulator, NULL,
7084                   _clutter_marshal_BOOLEAN__BOXED,
7085                   G_TYPE_BOOLEAN, 1,
7086                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7087   /**
7088    * ClutterActor::key-press-event:
7089    * @actor: the actor which received the event
7090    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7091    *
7092    * The ::key-press-event signal is emitted each time a keyboard button
7093    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7094    *
7095    * Return value: %TRUE if the event has been handled by the actor,
7096    *   or %FALSE to continue the emission.
7097    *
7098    * Since: 0.6
7099    */
7100   actor_signals[KEY_PRESS_EVENT] =
7101     g_signal_new (I_("key-press-event"),
7102                   G_TYPE_FROM_CLASS (object_class),
7103                   G_SIGNAL_RUN_LAST,
7104                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7105                   _clutter_boolean_handled_accumulator, NULL,
7106                   _clutter_marshal_BOOLEAN__BOXED,
7107                   G_TYPE_BOOLEAN, 1,
7108                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7109   /**
7110    * ClutterActor::key-release-event:
7111    * @actor: the actor which received the event
7112    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7113    *
7114    * The ::key-release-event signal is emitted each time a keyboard button
7115    * is released while @actor has key focus (see
7116    * clutter_stage_set_key_focus()).
7117    *
7118    * Return value: %TRUE if the event has been handled by the actor,
7119    *   or %FALSE to continue the emission.
7120    *
7121    * Since: 0.6
7122    */
7123   actor_signals[KEY_RELEASE_EVENT] =
7124     g_signal_new (I_("key-release-event"),
7125                   G_TYPE_FROM_CLASS (object_class),
7126                   G_SIGNAL_RUN_LAST,
7127                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7128                   _clutter_boolean_handled_accumulator, NULL,
7129                   _clutter_marshal_BOOLEAN__BOXED,
7130                   G_TYPE_BOOLEAN, 1,
7131                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7132   /**
7133    * ClutterActor::motion-event:
7134    * @actor: the actor which received the event
7135    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7136    *
7137    * The ::motion-event signal is emitted each time the mouse pointer is
7138    * moved over @actor.
7139    *
7140    * Return value: %TRUE if the event has been handled by the actor,
7141    *   or %FALSE to continue the emission.
7142    *
7143    * Since: 0.6
7144    */
7145   actor_signals[MOTION_EVENT] =
7146     g_signal_new (I_("motion-event"),
7147                   G_TYPE_FROM_CLASS (object_class),
7148                   G_SIGNAL_RUN_LAST,
7149                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7150                   _clutter_boolean_handled_accumulator, NULL,
7151                   _clutter_marshal_BOOLEAN__BOXED,
7152                   G_TYPE_BOOLEAN, 1,
7153                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7154
7155   /**
7156    * ClutterActor::key-focus-in:
7157    * @actor: the actor which now has key focus
7158    *
7159    * The ::key-focus-in signal is emitted when @actor receives key focus.
7160    *
7161    * Since: 0.6
7162    */
7163   actor_signals[KEY_FOCUS_IN] =
7164     g_signal_new (I_("key-focus-in"),
7165                   G_TYPE_FROM_CLASS (object_class),
7166                   G_SIGNAL_RUN_LAST,
7167                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7168                   NULL, NULL,
7169                   _clutter_marshal_VOID__VOID,
7170                   G_TYPE_NONE, 0);
7171
7172   /**
7173    * ClutterActor::key-focus-out:
7174    * @actor: the actor which now has key focus
7175    *
7176    * The ::key-focus-out signal is emitted when @actor loses key focus.
7177    *
7178    * Since: 0.6
7179    */
7180   actor_signals[KEY_FOCUS_OUT] =
7181     g_signal_new (I_("key-focus-out"),
7182                   G_TYPE_FROM_CLASS (object_class),
7183                   G_SIGNAL_RUN_LAST,
7184                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7185                   NULL, NULL,
7186                   _clutter_marshal_VOID__VOID,
7187                   G_TYPE_NONE, 0);
7188
7189   /**
7190    * ClutterActor::enter-event:
7191    * @actor: the actor which the pointer has entered.
7192    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7193    *
7194    * The ::enter-event signal is emitted when the pointer enters the @actor
7195    *
7196    * Return value: %TRUE if the event has been handled by the actor,
7197    *   or %FALSE to continue the emission.
7198    *
7199    * Since: 0.6
7200    */
7201   actor_signals[ENTER_EVENT] =
7202     g_signal_new (I_("enter-event"),
7203                   G_TYPE_FROM_CLASS (object_class),
7204                   G_SIGNAL_RUN_LAST,
7205                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7206                   _clutter_boolean_handled_accumulator, NULL,
7207                   _clutter_marshal_BOOLEAN__BOXED,
7208                   G_TYPE_BOOLEAN, 1,
7209                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7210
7211   /**
7212    * ClutterActor::leave-event:
7213    * @actor: the actor which the pointer has left
7214    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7215    *
7216    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7217    *
7218    * Return value: %TRUE if the event has been handled by the actor,
7219    *   or %FALSE to continue the emission.
7220    *
7221    * Since: 0.6
7222    */
7223   actor_signals[LEAVE_EVENT] =
7224     g_signal_new (I_("leave-event"),
7225                   G_TYPE_FROM_CLASS (object_class),
7226                   G_SIGNAL_RUN_LAST,
7227                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7228                   _clutter_boolean_handled_accumulator, NULL,
7229                   _clutter_marshal_BOOLEAN__BOXED,
7230                   G_TYPE_BOOLEAN, 1,
7231                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7232
7233   /**
7234    * ClutterActor::captured-event:
7235    * @actor: the actor which received the signal
7236    * @event: a #ClutterEvent
7237    *
7238    * The ::captured-event signal is emitted when an event is captured
7239    * by Clutter. This signal will be emitted starting from the top-level
7240    * container (the #ClutterStage) to the actor which received the event
7241    * going down the hierarchy. This signal can be used to intercept every
7242    * event before the specialized events (like
7243    * ClutterActor::button-press-event or ::key-released-event) are
7244    * emitted.
7245    *
7246    * Return value: %TRUE if the event has been handled by the actor,
7247    *   or %FALSE to continue the emission.
7248    *
7249    * Since: 0.6
7250    */
7251   actor_signals[CAPTURED_EVENT] =
7252     g_signal_new (I_("captured-event"),
7253                   G_TYPE_FROM_CLASS (object_class),
7254                   G_SIGNAL_RUN_LAST,
7255                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7256                   _clutter_boolean_handled_accumulator, NULL,
7257                   _clutter_marshal_BOOLEAN__BOXED,
7258                   G_TYPE_BOOLEAN, 1,
7259                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7260
7261   /**
7262    * ClutterActor::paint:
7263    * @actor: the #ClutterActor that received the signal
7264    *
7265    * The ::paint signal is emitted each time an actor is being painted.
7266    *
7267    * Subclasses of #ClutterActor should override the class signal handler
7268    * and paint themselves in that function.
7269    *
7270    * It is possible to connect a handler to the ::paint signal in order
7271    * to set up some custom aspect of a paint.
7272    *
7273    * Since: 0.8
7274    */
7275   actor_signals[PAINT] =
7276     g_signal_new (I_("paint"),
7277                   G_TYPE_FROM_CLASS (object_class),
7278                   G_SIGNAL_RUN_LAST |
7279                   G_SIGNAL_NO_HOOKS,
7280                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7281                   NULL, NULL,
7282                   _clutter_marshal_VOID__VOID,
7283                   G_TYPE_NONE, 0);
7284   /**
7285    * ClutterActor::realize:
7286    * @actor: the #ClutterActor that received the signal
7287    *
7288    * The ::realize signal is emitted each time an actor is being
7289    * realized.
7290    *
7291    * Since: 0.8
7292    */
7293   actor_signals[REALIZE] =
7294     g_signal_new (I_("realize"),
7295                   G_TYPE_FROM_CLASS (object_class),
7296                   G_SIGNAL_RUN_LAST,
7297                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7298                   NULL, NULL,
7299                   _clutter_marshal_VOID__VOID,
7300                   G_TYPE_NONE, 0);
7301   /**
7302    * ClutterActor::unrealize:
7303    * @actor: the #ClutterActor that received the signal
7304    *
7305    * The ::unrealize signal is emitted each time an actor is being
7306    * unrealized.
7307    *
7308    * Since: 0.8
7309    */
7310   actor_signals[UNREALIZE] =
7311     g_signal_new (I_("unrealize"),
7312                   G_TYPE_FROM_CLASS (object_class),
7313                   G_SIGNAL_RUN_LAST,
7314                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7315                   NULL, NULL,
7316                   _clutter_marshal_VOID__VOID,
7317                   G_TYPE_NONE, 0);
7318
7319   /**
7320    * ClutterActor::pick:
7321    * @actor: the #ClutterActor that received the signal
7322    * @color: the #ClutterColor to be used when picking
7323    *
7324    * The ::pick signal is emitted each time an actor is being painted
7325    * in "pick mode". The pick mode is used to identify the actor during
7326    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7327    * The actor should paint its shape using the passed @pick_color.
7328    *
7329    * Subclasses of #ClutterActor should override the class signal handler
7330    * and paint themselves in that function.
7331    *
7332    * It is possible to connect a handler to the ::pick signal in order
7333    * to set up some custom aspect of a paint in pick mode.
7334    *
7335    * Since: 1.0
7336    */
7337   actor_signals[PICK] =
7338     g_signal_new (I_("pick"),
7339                   G_TYPE_FROM_CLASS (object_class),
7340                   G_SIGNAL_RUN_LAST,
7341                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7342                   NULL, NULL,
7343                   _clutter_marshal_VOID__BOXED,
7344                   G_TYPE_NONE, 1,
7345                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7346
7347   /**
7348    * ClutterActor::allocation-changed:
7349    * @actor: the #ClutterActor that emitted the signal
7350    * @box: a #ClutterActorBox with the new allocation
7351    * @flags: #ClutterAllocationFlags for the allocation
7352    *
7353    * The ::allocation-changed signal is emitted when the
7354    * #ClutterActor:allocation property changes. Usually, application
7355    * code should just use the notifications for the :allocation property
7356    * but if you want to track the allocation flags as well, for instance
7357    * to know whether the absolute origin of @actor changed, then you might
7358    * want use this signal instead.
7359    *
7360    * Since: 1.0
7361    */
7362   actor_signals[ALLOCATION_CHANGED] =
7363     g_signal_new (I_("allocation-changed"),
7364                   G_TYPE_FROM_CLASS (object_class),
7365                   G_SIGNAL_RUN_LAST,
7366                   0,
7367                   NULL, NULL,
7368                   _clutter_marshal_VOID__BOXED_FLAGS,
7369                   G_TYPE_NONE, 2,
7370                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7371                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7372
7373   /**
7374    * ClutterActor::transitions-completed:
7375    * @actor: a #ClutterActor
7376    *
7377    * The ::transitions-completed signal is emitted once all transitions
7378    * involving @actor are complete.
7379    *
7380    * Since: 1.10
7381    */
7382   actor_signals[TRANSITIONS_COMPLETED] =
7383     g_signal_new (I_("transitions-completed"),
7384                   G_TYPE_FROM_CLASS (object_class),
7385                   G_SIGNAL_RUN_LAST,
7386                   0,
7387                   NULL, NULL,
7388                   _clutter_marshal_VOID__VOID,
7389                   G_TYPE_NONE, 0);
7390 }
7391
7392 static void
7393 clutter_actor_init (ClutterActor *self)
7394 {
7395   ClutterActorPrivate *priv;
7396
7397   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7398
7399   priv->id = _clutter_context_acquire_id (self);
7400   priv->pick_id = -1;
7401
7402   priv->opacity = 0xff;
7403   priv->show_on_set_parent = TRUE;
7404
7405   priv->needs_width_request = TRUE;
7406   priv->needs_height_request = TRUE;
7407   priv->needs_allocation = TRUE;
7408
7409   priv->cached_width_age = 1;
7410   priv->cached_height_age = 1;
7411
7412   priv->opacity_override = -1;
7413   priv->enable_model_view_transform = TRUE;
7414
7415   /* Initialize an empty paint volume to start with */
7416   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7417   priv->last_paint_volume_valid = TRUE;
7418
7419   priv->transform_valid = FALSE;
7420
7421   /* the default is to stretch the content, to match the
7422    * current behaviour of basically all actors. also, it's
7423    * the easiest thing to compute.
7424    */
7425   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7426   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7427   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7428
7429   /* this flag will be set to TRUE if the actor gets a child
7430    * or if the [xy]-expand flags are explicitly set; until
7431    * then, the actor does not need to expand.
7432    *
7433    * this also allows us to avoid computing the expand flag
7434    * when building up a scene.
7435    */
7436   priv->needs_compute_expand = FALSE;
7437 }
7438
7439 /**
7440  * clutter_actor_new:
7441  *
7442  * Creates a new #ClutterActor.
7443  *
7444  * A newly created actor has a floating reference, which will be sunk
7445  * when it is added to another actor.
7446  *
7447  * Return value: (transfer full): the newly created #ClutterActor
7448  *
7449  * Since: 1.10
7450  */
7451 ClutterActor *
7452 clutter_actor_new (void)
7453 {
7454   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7455 }
7456
7457 /**
7458  * clutter_actor_destroy:
7459  * @self: a #ClutterActor
7460  *
7461  * Destroys an actor.  When an actor is destroyed, it will break any
7462  * references it holds to other objects.  If the actor is inside a
7463  * container, the actor will be removed.
7464  *
7465  * When you destroy a container, its children will be destroyed as well.
7466  *
7467  * Note: you cannot destroy the #ClutterStage returned by
7468  * clutter_stage_get_default().
7469  */
7470 void
7471 clutter_actor_destroy (ClutterActor *self)
7472 {
7473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7474
7475   g_object_ref (self);
7476
7477   /* avoid recursion while destroying */
7478   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7479     {
7480       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7481
7482       g_object_run_dispose (G_OBJECT (self));
7483
7484       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7485     }
7486
7487   g_object_unref (self);
7488 }
7489
7490 void
7491 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7492                                     ClutterPaintVolume *clip)
7493 {
7494   ClutterActorPrivate *priv = self->priv;
7495   ClutterPaintVolume *pv;
7496   gboolean clipped;
7497
7498   /* Remove queue entry early in the process, otherwise a new
7499      queue_redraw() during signal handling could put back this
7500      object in the stage redraw list (but the entry is freed as
7501      soon as we return from this function, causing a segfault
7502      later)
7503   */
7504   priv->queue_redraw_entry = NULL;
7505
7506   /* If we've been explicitly passed a clip volume then there's
7507    * nothing more to calculate, but otherwise the only thing we know
7508    * is that the change is constrained to the given actor.
7509    *
7510    * The idea is that if we know the paint volume for where the actor
7511    * was last drawn (in eye coordinates) and we also have the paint
7512    * volume for where it will be drawn next (in actor coordinates)
7513    * then if we queue a redraw for both these volumes that will cover
7514    * everything that needs to be redrawn to clear the old view and
7515    * show the latest view of the actor.
7516    *
7517    * Don't clip this redraw if we don't know what position we had for
7518    * the previous redraw since we don't know where to set the clip so
7519    * it will clear the actor as it is currently.
7520    */
7521   if (clip)
7522     {
7523       _clutter_actor_set_queue_redraw_clip (self, clip);
7524       clipped = TRUE;
7525     }
7526   else if (G_LIKELY (priv->last_paint_volume_valid))
7527     {
7528       pv = _clutter_actor_get_paint_volume_mutable (self);
7529       if (pv)
7530         {
7531           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7532
7533           /* make sure we redraw the actors old position... */
7534           _clutter_actor_set_queue_redraw_clip (stage,
7535                                                 &priv->last_paint_volume);
7536           _clutter_actor_signal_queue_redraw (stage, stage);
7537           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7538
7539           /* XXX: Ideally the redraw signal would take a clip volume
7540            * argument, but that would be an ABI break. Until we can
7541            * break the ABI we pass the argument out-of-band
7542            */
7543
7544           /* setup the clip for the actors new position... */
7545           _clutter_actor_set_queue_redraw_clip (self, pv);
7546           clipped = TRUE;
7547         }
7548       else
7549         clipped = FALSE;
7550     }
7551   else
7552     clipped = FALSE;
7553
7554   _clutter_actor_signal_queue_redraw (self, self);
7555
7556   /* Just in case anyone is manually firing redraw signals without
7557    * using the public queue_redraw() API we are careful to ensure that
7558    * our out-of-band clip member is cleared before returning...
7559    *
7560    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7561    */
7562   if (G_LIKELY (clipped))
7563     _clutter_actor_set_queue_redraw_clip (self, NULL);
7564 }
7565
7566 static void
7567 _clutter_actor_get_allocation_clip (ClutterActor *self,
7568                                     ClutterActorBox *clip)
7569 {
7570   ClutterActorBox allocation;
7571
7572   /* XXX: we don't care if we get an out of date allocation here
7573    * because clutter_actor_queue_redraw_with_clip knows to ignore
7574    * the clip if the actor's allocation is invalid.
7575    *
7576    * This is noted because clutter_actor_get_allocation_box does some
7577    * unnecessary work to support buggy code with a comment suggesting
7578    * that it could be changed later which would be good for this use
7579    * case!
7580    */
7581   clutter_actor_get_allocation_box (self, &allocation);
7582
7583   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7584    * actor's own coordinate space but the allocation is in parent
7585    * coordinates */
7586   clip->x1 = 0;
7587   clip->y1 = 0;
7588   clip->x2 = allocation.x2 - allocation.x1;
7589   clip->y2 = allocation.y2 - allocation.y1;
7590 }
7591
7592 void
7593 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7594                                   ClutterRedrawFlags  flags,
7595                                   ClutterPaintVolume *volume,
7596                                   ClutterEffect      *effect)
7597 {
7598   ClutterActorPrivate *priv = self->priv;
7599   ClutterPaintVolume allocation_pv;
7600   ClutterPaintVolume *pv;
7601   gboolean should_free_pv;
7602   ClutterActor *stage;
7603
7604   /* Here's an outline of the actor queue redraw mechanism:
7605    *
7606    * The process starts in one of the following two functions which
7607    * are wrappers for this function:
7608    * clutter_actor_queue_redraw
7609    * _clutter_actor_queue_redraw_with_clip
7610    *
7611    * additionally, an effect can queue a redraw by wrapping this
7612    * function in clutter_effect_queue_rerun
7613    *
7614    * This functions queues an entry in a list associated with the
7615    * stage which is a list of actors that queued a redraw while
7616    * updating the timelines, performing layouting and processing other
7617    * mainloop sources before the next paint starts.
7618    *
7619    * We aim to minimize the processing done at this point because
7620    * there is a good chance other events will happen while updating
7621    * the scenegraph that would invalidate any expensive work we might
7622    * otherwise try to do here. For example we don't try and resolve
7623    * the screen space bounding box of an actor at this stage so as to
7624    * minimize how much of the screen redraw because it's possible
7625    * something else will happen which will force a full redraw anyway.
7626    *
7627    * When all updates are complete and we come to paint the stage then
7628    * we iterate this list and actually emit the "queue-redraw" signals
7629    * for each of the listed actors which will bubble up to the stage
7630    * for each actor and at that point we will transform the actors
7631    * paint volume into screen coordinates to determine the clip region
7632    * for what needs to be redrawn in the next paint.
7633    *
7634    * Besides minimizing redundant work another reason for this
7635    * deferred design is that it's more likely we will be able to
7636    * determine the paint volume of an actor once we've finished
7637    * updating the scenegraph because its allocation should be up to
7638    * date. NB: If we can't determine an actors paint volume then we
7639    * can't automatically queue a clipped redraw which can make a big
7640    * difference to performance.
7641    *
7642    * So the control flow goes like this:
7643    * One of clutter_actor_queue_redraw,
7644    *        _clutter_actor_queue_redraw_with_clip
7645    *     or clutter_effect_queue_rerun
7646    *
7647    * then control moves to:
7648    *   _clutter_stage_queue_actor_redraw
7649    *
7650    * later during _clutter_stage_do_update, once relayouting is done
7651    * and the scenegraph has been updated we will call:
7652    * _clutter_stage_finish_queue_redraws
7653    *
7654    * _clutter_stage_finish_queue_redraws will call
7655    * _clutter_actor_finish_queue_redraw for each listed actor.
7656    * Note: actors *are* allowed to queue further redraws during this
7657    * process (considering clone actors or texture_new_from_actor which
7658    * respond to their source queueing a redraw by queuing a redraw
7659    * themselves). We repeat the process until the list is empty.
7660    *
7661    * This will result in the "queue-redraw" signal being fired for
7662    * each actor which will pass control to the default signal handler:
7663    * clutter_actor_real_queue_redraw
7664    *
7665    * This will bubble up to the stages handler:
7666    * clutter_stage_real_queue_redraw
7667    *
7668    * clutter_stage_real_queue_redraw will transform the actors paint
7669    * volume into screen space and add it as a clip region for the next
7670    * paint.
7671    */
7672
7673   /* ignore queueing a redraw for actors being destroyed */
7674   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7675     return;
7676
7677   stage = _clutter_actor_get_stage_internal (self);
7678
7679   /* Ignore queueing a redraw for actors not descended from a stage */
7680   if (stage == NULL)
7681     return;
7682
7683   /* ignore queueing a redraw on stages that are being destroyed */
7684   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7685     return;
7686
7687   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7688     {
7689       ClutterActorBox allocation_clip;
7690       ClutterVertex origin;
7691
7692       /* If the actor doesn't have a valid allocation then we will
7693        * queue a full stage redraw. */
7694       if (priv->needs_allocation)
7695         {
7696           /* NB: NULL denotes an undefined clip which will result in a
7697            * full redraw... */
7698           _clutter_actor_set_queue_redraw_clip (self, NULL);
7699           _clutter_actor_signal_queue_redraw (self, self);
7700           return;
7701         }
7702
7703       _clutter_paint_volume_init_static (&allocation_pv, self);
7704       pv = &allocation_pv;
7705
7706       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7707
7708       origin.x = allocation_clip.x1;
7709       origin.y = allocation_clip.y1;
7710       origin.z = 0;
7711       clutter_paint_volume_set_origin (pv, &origin);
7712       clutter_paint_volume_set_width (pv,
7713                                       allocation_clip.x2 - allocation_clip.x1);
7714       clutter_paint_volume_set_height (pv,
7715                                        allocation_clip.y2 -
7716                                        allocation_clip.y1);
7717       should_free_pv = TRUE;
7718     }
7719   else
7720     {
7721       pv = volume;
7722       should_free_pv = FALSE;
7723     }
7724
7725   self->priv->queue_redraw_entry =
7726     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7727                                        priv->queue_redraw_entry,
7728                                        self,
7729                                        pv);
7730
7731   if (should_free_pv)
7732     clutter_paint_volume_free (pv);
7733
7734   /* If this is the first redraw queued then we can directly use the
7735      effect parameter */
7736   if (!priv->is_dirty)
7737     priv->effect_to_redraw = effect;
7738   /* Otherwise we need to merge it with the existing effect parameter */
7739   else if (effect != NULL)
7740     {
7741       /* If there's already an effect then we need to use whichever is
7742          later in the chain of actors. Otherwise a full redraw has
7743          already been queued on the actor so we need to ignore the
7744          effect parameter */
7745       if (priv->effect_to_redraw != NULL)
7746         {
7747           if (priv->effects == NULL)
7748             g_warning ("Redraw queued with an effect that is "
7749                        "not applied to the actor");
7750           else
7751             {
7752               const GList *l;
7753
7754               for (l = _clutter_meta_group_peek_metas (priv->effects);
7755                    l != NULL;
7756                    l = l->next)
7757                 {
7758                   if (l->data == priv->effect_to_redraw ||
7759                       l->data == effect)
7760                     priv->effect_to_redraw = l->data;
7761                 }
7762             }
7763         }
7764     }
7765   else
7766     {
7767       /* If no effect is specified then we need to redraw the whole
7768          actor */
7769       priv->effect_to_redraw = NULL;
7770     }
7771
7772   priv->is_dirty = TRUE;
7773 }
7774
7775 /**
7776  * clutter_actor_queue_redraw:
7777  * @self: A #ClutterActor
7778  *
7779  * Queues up a redraw of an actor and any children. The redraw occurs
7780  * once the main loop becomes idle (after the current batch of events
7781  * has been processed, roughly).
7782  *
7783  * Applications rarely need to call this, as redraws are handled
7784  * automatically by modification functions.
7785  *
7786  * This function will not do anything if @self is not visible, or
7787  * if the actor is inside an invisible part of the scenegraph.
7788  *
7789  * Also be aware that painting is a NOP for actors with an opacity of
7790  * 0
7791  *
7792  * When you are implementing a custom actor you must queue a redraw
7793  * whenever some private state changes that will affect painting or
7794  * picking of your actor.
7795  */
7796 void
7797 clutter_actor_queue_redraw (ClutterActor *self)
7798 {
7799   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7800
7801   _clutter_actor_queue_redraw_full (self,
7802                                     0, /* flags */
7803                                     NULL, /* clip volume */
7804                                     NULL /* effect */);
7805 }
7806
7807 /*< private >
7808  * _clutter_actor_queue_redraw_with_clip:
7809  * @self: A #ClutterActor
7810  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7811  *   this queue redraw.
7812  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7813  *   redrawn or %NULL if you are just using a @flag to state your
7814  *   desired clipping.
7815  *
7816  * Queues up a clipped redraw of an actor and any children. The redraw
7817  * occurs once the main loop becomes idle (after the current batch of
7818  * events has been processed, roughly).
7819  *
7820  * If no flags are given the clip volume is defined by @volume
7821  * specified in actor coordinates and tells Clutter that only content
7822  * within this volume has been changed so Clutter can optionally
7823  * optimize the redraw.
7824  *
7825  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7826  * should be %NULL and this tells Clutter to use the actor's current
7827  * allocation as a clip box. This flag can only be used for 2D actors,
7828  * because any actor with depth may be projected outside its
7829  * allocation.
7830  *
7831  * Applications rarely need to call this, as redraws are handled
7832  * automatically by modification functions.
7833  *
7834  * This function will not do anything if @self is not visible, or if
7835  * the actor is inside an invisible part of the scenegraph.
7836  *
7837  * Also be aware that painting is a NOP for actors with an opacity of
7838  * 0
7839  *
7840  * When you are implementing a custom actor you must queue a redraw
7841  * whenever some private state changes that will affect painting or
7842  * picking of your actor.
7843  */
7844 void
7845 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7846                                        ClutterRedrawFlags  flags,
7847                                        ClutterPaintVolume *volume)
7848 {
7849   _clutter_actor_queue_redraw_full (self,
7850                                     flags, /* flags */
7851                                     volume, /* clip volume */
7852                                     NULL /* effect */);
7853 }
7854
7855 static void
7856 _clutter_actor_queue_only_relayout (ClutterActor *self)
7857 {
7858   ClutterActorPrivate *priv = self->priv;
7859
7860   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7861     return;
7862
7863   if (priv->needs_width_request &&
7864       priv->needs_height_request &&
7865       priv->needs_allocation)
7866     return; /* save some cpu cycles */
7867
7868 #if CLUTTER_ENABLE_DEBUG
7869   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7870     {
7871       g_warning ("The actor '%s' is currently inside an allocation "
7872                  "cycle; calling clutter_actor_queue_relayout() is "
7873                  "not recommended",
7874                  _clutter_actor_get_debug_name (self));
7875     }
7876 #endif /* CLUTTER_ENABLE_DEBUG */
7877
7878   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7879 }
7880
7881 /**
7882  * clutter_actor_queue_redraw_with_clip:
7883  * @self: a #ClutterActor
7884  * @clip: (allow-none): a rectangular clip region, or %NULL
7885  *
7886  * Queues a redraw on @self limited to a specific, actor-relative
7887  * rectangular area.
7888  *
7889  * If @clip is %NULL this function is equivalent to
7890  * clutter_actor_queue_redraw().
7891  *
7892  * Since: 1.10
7893  */
7894 void
7895 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7896                                       const cairo_rectangle_int_t *clip)
7897 {
7898   ClutterPaintVolume volume;
7899   ClutterVertex origin;
7900
7901   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7902
7903   if (clip == NULL)
7904     {
7905       clutter_actor_queue_redraw (self);
7906       return;
7907     }
7908
7909   _clutter_paint_volume_init_static (&volume, self);
7910
7911   origin.x = clip->x;
7912   origin.y = clip->y;
7913   origin.z = 0.0f;
7914
7915   clutter_paint_volume_set_origin (&volume, &origin);
7916   clutter_paint_volume_set_width (&volume, clip->width);
7917   clutter_paint_volume_set_height (&volume, clip->height);
7918
7919   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7920
7921   clutter_paint_volume_free (&volume);
7922 }
7923
7924 /**
7925  * clutter_actor_queue_relayout:
7926  * @self: A #ClutterActor
7927  *
7928  * Indicates that the actor's size request or other layout-affecting
7929  * properties may have changed. This function is used inside #ClutterActor
7930  * subclass implementations, not by applications directly.
7931  *
7932  * Queueing a new layout automatically queues a redraw as well.
7933  *
7934  * Since: 0.8
7935  */
7936 void
7937 clutter_actor_queue_relayout (ClutterActor *self)
7938 {
7939   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7940
7941   _clutter_actor_queue_only_relayout (self);
7942   clutter_actor_queue_redraw (self);
7943 }
7944
7945 /**
7946  * clutter_actor_get_preferred_size:
7947  * @self: a #ClutterActor
7948  * @min_width_p: (out) (allow-none): return location for the minimum
7949  *   width, or %NULL
7950  * @min_height_p: (out) (allow-none): return location for the minimum
7951  *   height, or %NULL
7952  * @natural_width_p: (out) (allow-none): return location for the natural
7953  *   width, or %NULL
7954  * @natural_height_p: (out) (allow-none): return location for the natural
7955  *   height, or %NULL
7956  *
7957  * Computes the preferred minimum and natural size of an actor, taking into
7958  * account the actor's geometry management (either height-for-width
7959  * or width-for-height).
7960  *
7961  * The width and height used to compute the preferred height and preferred
7962  * width are the actor's natural ones.
7963  *
7964  * If you need to control the height for the preferred width, or the width for
7965  * the preferred height, you should use clutter_actor_get_preferred_width()
7966  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7967  * geometry management using the #ClutterActor:request-mode property.
7968  *
7969  * Since: 0.8
7970  */
7971 void
7972 clutter_actor_get_preferred_size (ClutterActor *self,
7973                                   gfloat       *min_width_p,
7974                                   gfloat       *min_height_p,
7975                                   gfloat       *natural_width_p,
7976                                   gfloat       *natural_height_p)
7977 {
7978   ClutterActorPrivate *priv;
7979   gfloat min_width, min_height;
7980   gfloat natural_width, natural_height;
7981
7982   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7983
7984   priv = self->priv;
7985
7986   min_width = min_height = 0;
7987   natural_width = natural_height = 0;
7988
7989   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7990     {
7991       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7992       clutter_actor_get_preferred_width (self, -1,
7993                                          &min_width,
7994                                          &natural_width);
7995       clutter_actor_get_preferred_height (self, natural_width,
7996                                           &min_height,
7997                                           &natural_height);
7998     }
7999   else
8000     {
8001       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
8002       clutter_actor_get_preferred_height (self, -1,
8003                                           &min_height,
8004                                           &natural_height);
8005       clutter_actor_get_preferred_width (self, natural_height,
8006                                          &min_width,
8007                                          &natural_width);
8008     }
8009
8010   if (min_width_p)
8011     *min_width_p = min_width;
8012
8013   if (min_height_p)
8014     *min_height_p = min_height;
8015
8016   if (natural_width_p)
8017     *natural_width_p = natural_width;
8018
8019   if (natural_height_p)
8020     *natural_height_p = natural_height;
8021 }
8022
8023 /*< private >
8024  * effective_align:
8025  * @align: a #ClutterActorAlign
8026  * @direction: a #ClutterTextDirection
8027  *
8028  * Retrieves the correct alignment depending on the text direction
8029  *
8030  * Return value: the effective alignment
8031  */
8032 static ClutterActorAlign
8033 effective_align (ClutterActorAlign    align,
8034                  ClutterTextDirection direction)
8035 {
8036   ClutterActorAlign res;
8037
8038   switch (align)
8039     {
8040     case CLUTTER_ACTOR_ALIGN_START:
8041       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8042           ? CLUTTER_ACTOR_ALIGN_END
8043           : CLUTTER_ACTOR_ALIGN_START;
8044       break;
8045
8046     case CLUTTER_ACTOR_ALIGN_END:
8047       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8048           ? CLUTTER_ACTOR_ALIGN_START
8049           : CLUTTER_ACTOR_ALIGN_END;
8050       break;
8051
8052     default:
8053       res = align;
8054       break;
8055     }
8056
8057   return res;
8058 }
8059
8060 /*< private >
8061  * _clutter_actor_get_effective_x_align:
8062  * @self: a #ClutterActor
8063  *
8064  * Retrieves the effective horizontal alignment, taking into
8065  * consideration the text direction of @self.
8066  *
8067  * Return value: the effective horizontal alignment
8068  */
8069 ClutterActorAlign
8070 _clutter_actor_get_effective_x_align (ClutterActor *self)
8071 {
8072   return effective_align (clutter_actor_get_x_align (self),
8073                           clutter_actor_get_text_direction (self));
8074 }
8075
8076 static inline void
8077 adjust_for_margin (float  margin_start,
8078                    float  margin_end,
8079                    float *minimum_size,
8080                    float *natural_size,
8081                    float *allocated_start,
8082                    float *allocated_end)
8083 {
8084   *minimum_size -= (margin_start + margin_end);
8085   *natural_size -= (margin_start + margin_end);
8086   *allocated_start += margin_start;
8087   *allocated_end -= margin_end;
8088 }
8089
8090 static inline void
8091 adjust_for_alignment (ClutterActorAlign  alignment,
8092                       float              natural_size,
8093                       float             *allocated_start,
8094                       float             *allocated_end)
8095 {
8096   float allocated_size = *allocated_end - *allocated_start;
8097
8098   switch (alignment)
8099     {
8100     case CLUTTER_ACTOR_ALIGN_FILL:
8101       /* do nothing */
8102       break;
8103
8104     case CLUTTER_ACTOR_ALIGN_START:
8105       /* keep start */
8106       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8107       break;
8108
8109     case CLUTTER_ACTOR_ALIGN_END:
8110       if (allocated_size > natural_size)
8111         {
8112           *allocated_start += (allocated_size - natural_size);
8113           *allocated_end = *allocated_start + natural_size;
8114         }
8115       break;
8116
8117     case CLUTTER_ACTOR_ALIGN_CENTER:
8118       if (allocated_size > natural_size)
8119         {
8120           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8121           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8122         }
8123       break;
8124     }
8125 }
8126
8127 /*< private >
8128  * clutter_actor_adjust_width:
8129  * @self: a #ClutterActor
8130  * @minimum_width: (inout): the actor's preferred minimum width, which
8131  *   will be adjusted depending on the margin
8132  * @natural_width: (inout): the actor's preferred natural width, which
8133  *   will be adjusted depending on the margin
8134  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8135  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8136  *
8137  * Adjusts the preferred and allocated position and size of an actor,
8138  * depending on the margin and alignment properties.
8139  */
8140 static void
8141 clutter_actor_adjust_width (ClutterActor *self,
8142                             gfloat       *minimum_width,
8143                             gfloat       *natural_width,
8144                             gfloat       *adjusted_x1,
8145                             gfloat       *adjusted_x2)
8146 {
8147   ClutterTextDirection text_dir;
8148   const ClutterLayoutInfo *info;
8149
8150   info = _clutter_actor_get_layout_info_or_defaults (self);
8151   text_dir = clutter_actor_get_text_direction (self);
8152
8153   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8154
8155   /* this will tweak natural_width to remove the margin, so that
8156    * adjust_for_alignment() will use the correct size
8157    */
8158   adjust_for_margin (info->margin.left, info->margin.right,
8159                      minimum_width, natural_width,
8160                      adjusted_x1, adjusted_x2);
8161
8162   adjust_for_alignment (effective_align (info->x_align, text_dir),
8163                         *natural_width,
8164                         adjusted_x1, adjusted_x2);
8165 }
8166
8167 /*< private >
8168  * clutter_actor_adjust_height:
8169  * @self: a #ClutterActor
8170  * @minimum_height: (inout): the actor's preferred minimum height, which
8171  *   will be adjusted depending on the margin
8172  * @natural_height: (inout): the actor's preferred natural height, which
8173  *   will be adjusted depending on the margin
8174  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8175  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8176  *
8177  * Adjusts the preferred and allocated position and size of an actor,
8178  * depending on the margin and alignment properties.
8179  */
8180 static void
8181 clutter_actor_adjust_height (ClutterActor *self,
8182                              gfloat       *minimum_height,
8183                              gfloat       *natural_height,
8184                              gfloat       *adjusted_y1,
8185                              gfloat       *adjusted_y2)
8186 {
8187   const ClutterLayoutInfo *info;
8188
8189   info = _clutter_actor_get_layout_info_or_defaults (self);
8190
8191   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8192
8193   /* this will tweak natural_height to remove the margin, so that
8194    * adjust_for_alignment() will use the correct size
8195    */
8196   adjust_for_margin (info->margin.top, info->margin.bottom,
8197                      minimum_height, natural_height,
8198                      adjusted_y1,
8199                      adjusted_y2);
8200
8201   /* we don't use effective_align() here, because text direction
8202    * only affects the horizontal axis
8203    */
8204   adjust_for_alignment (info->y_align,
8205                         *natural_height,
8206                         adjusted_y1,
8207                         adjusted_y2);
8208
8209 }
8210
8211 /* looks for a cached size request for this for_size. If not
8212  * found, returns the oldest entry so it can be overwritten */
8213 static gboolean
8214 _clutter_actor_get_cached_size_request (gfloat         for_size,
8215                                         SizeRequest   *cached_size_requests,
8216                                         SizeRequest  **result)
8217 {
8218   guint i;
8219
8220   *result = &cached_size_requests[0];
8221
8222   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8223     {
8224       SizeRequest *sr;
8225
8226       sr = &cached_size_requests[i];
8227
8228       if (sr->age > 0 &&
8229           sr->for_size == for_size)
8230         {
8231           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8232           *result = sr;
8233           return TRUE;
8234         }
8235       else if (sr->age < (*result)->age)
8236         {
8237           *result = sr;
8238         }
8239     }
8240
8241   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8242
8243   return FALSE;
8244 }
8245
8246 /**
8247  * clutter_actor_get_preferred_width:
8248  * @self: A #ClutterActor
8249  * @for_height: available height when computing the preferred width,
8250  *   or a negative value to indicate that no height is defined
8251  * @min_width_p: (out) (allow-none): return location for minimum width,
8252  *   or %NULL
8253  * @natural_width_p: (out) (allow-none): return location for the natural
8254  *   width, or %NULL
8255  *
8256  * Computes the requested minimum and natural widths for an actor,
8257  * optionally depending on the specified height, or if they are
8258  * already computed, returns the cached values.
8259  *
8260  * An actor may not get its request - depending on the layout
8261  * manager that's in effect.
8262  *
8263  * A request should not incorporate the actor's scale or anchor point;
8264  * those transformations do not affect layout, only rendering.
8265  *
8266  * Since: 0.8
8267  */
8268 void
8269 clutter_actor_get_preferred_width (ClutterActor *self,
8270                                    gfloat        for_height,
8271                                    gfloat       *min_width_p,
8272                                    gfloat       *natural_width_p)
8273 {
8274   float request_min_width, request_natural_width;
8275   SizeRequest *cached_size_request;
8276   const ClutterLayoutInfo *info;
8277   ClutterActorPrivate *priv;
8278   gboolean found_in_cache;
8279
8280   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8281
8282   priv = self->priv;
8283
8284   info = _clutter_actor_get_layout_info_or_defaults (self);
8285
8286   /* we shortcircuit the case of a fixed size set using set_width() */
8287   if (priv->min_width_set && priv->natural_width_set)
8288     {
8289       if (min_width_p != NULL)
8290         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8291
8292       if (natural_width_p != NULL)
8293         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8294
8295       return;
8296     }
8297
8298   /* the remaining cases are:
8299    *
8300    *   - either min_width or natural_width have been set
8301    *   - neither min_width or natural_width have been set
8302    *
8303    * in both cases, we go through the cache (and through the actor in case
8304    * of cache misses) and determine the authoritative value depending on
8305    * the *_set flags.
8306    */
8307
8308   if (!priv->needs_width_request)
8309     {
8310       found_in_cache =
8311         _clutter_actor_get_cached_size_request (for_height,
8312                                                 priv->width_requests,
8313                                                 &cached_size_request);
8314     }
8315   else
8316     {
8317       /* if the actor needs a width request we use the first slot */
8318       found_in_cache = FALSE;
8319       cached_size_request = &priv->width_requests[0];
8320     }
8321
8322   if (!found_in_cache)
8323     {
8324       gfloat minimum_width, natural_width;
8325       ClutterActorClass *klass;
8326
8327       minimum_width = natural_width = 0;
8328
8329       /* adjust for the margin */
8330       if (for_height >= 0)
8331         {
8332           for_height -= (info->margin.top + info->margin.bottom);
8333           if (for_height < 0)
8334             for_height = 0;
8335         }
8336
8337       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8338
8339       klass = CLUTTER_ACTOR_GET_CLASS (self);
8340       klass->get_preferred_width (self, for_height,
8341                                   &minimum_width,
8342                                   &natural_width);
8343
8344       /* adjust for the margin */
8345       minimum_width += (info->margin.left + info->margin.right);
8346       natural_width += (info->margin.left + info->margin.right);
8347
8348       /* Due to accumulated float errors, it's better not to warn
8349        * on this, but just fix it.
8350        */
8351       if (natural_width < minimum_width)
8352         natural_width = minimum_width;
8353
8354       cached_size_request->min_size = minimum_width;
8355       cached_size_request->natural_size = natural_width;
8356       cached_size_request->for_size = for_height;
8357       cached_size_request->age = priv->cached_width_age;
8358
8359       priv->cached_width_age += 1;
8360       priv->needs_width_request = FALSE;
8361     }
8362
8363   if (!priv->min_width_set)
8364     request_min_width = cached_size_request->min_size;
8365   else
8366     request_min_width = info->margin.left
8367                       + info->minimum.width
8368                       + info->margin.right;
8369
8370   if (!priv->natural_width_set)
8371     request_natural_width = cached_size_request->natural_size;
8372   else
8373     request_natural_width = info->margin.left
8374                           + info->natural.width
8375                           + info->margin.right;
8376
8377   if (min_width_p)
8378     *min_width_p = request_min_width;
8379
8380   if (natural_width_p)
8381     *natural_width_p = request_natural_width;
8382 }
8383
8384 /**
8385  * clutter_actor_get_preferred_height:
8386  * @self: A #ClutterActor
8387  * @for_width: available width to assume in computing desired height,
8388  *   or a negative value to indicate that no width is defined
8389  * @min_height_p: (out) (allow-none): return location for minimum height,
8390  *   or %NULL
8391  * @natural_height_p: (out) (allow-none): return location for natural
8392  *   height, or %NULL
8393  *
8394  * Computes the requested minimum and natural heights for an actor,
8395  * or if they are already computed, returns the cached values.
8396  *
8397  * An actor may not get its request - depending on the layout
8398  * manager that's in effect.
8399  *
8400  * A request should not incorporate the actor's scale or anchor point;
8401  * those transformations do not affect layout, only rendering.
8402  *
8403  * Since: 0.8
8404  */
8405 void
8406 clutter_actor_get_preferred_height (ClutterActor *self,
8407                                     gfloat        for_width,
8408                                     gfloat       *min_height_p,
8409                                     gfloat       *natural_height_p)
8410 {
8411   float request_min_height, request_natural_height;
8412   SizeRequest *cached_size_request;
8413   const ClutterLayoutInfo *info;
8414   ClutterActorPrivate *priv;
8415   gboolean found_in_cache;
8416
8417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8418
8419   priv = self->priv;
8420
8421   info = _clutter_actor_get_layout_info_or_defaults (self);
8422
8423   /* we shortcircuit the case of a fixed size set using set_height() */
8424   if (priv->min_height_set && priv->natural_height_set)
8425     {
8426       if (min_height_p != NULL)
8427         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8428
8429       if (natural_height_p != NULL)
8430         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8431
8432       return;
8433     }
8434
8435   /* the remaining cases are:
8436    *
8437    *   - either min_height or natural_height have been set
8438    *   - neither min_height or natural_height have been set
8439    *
8440    * in both cases, we go through the cache (and through the actor in case
8441    * of cache misses) and determine the authoritative value depending on
8442    * the *_set flags.
8443    */
8444
8445   if (!priv->needs_height_request)
8446     {
8447       found_in_cache =
8448         _clutter_actor_get_cached_size_request (for_width,
8449                                                 priv->height_requests,
8450                                                 &cached_size_request);
8451     }
8452   else
8453     {
8454       found_in_cache = FALSE;
8455       cached_size_request = &priv->height_requests[0];
8456     }
8457
8458   if (!found_in_cache)
8459     {
8460       gfloat minimum_height, natural_height;
8461       ClutterActorClass *klass;
8462
8463       minimum_height = natural_height = 0;
8464
8465       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8466
8467       /* adjust for margin */
8468       if (for_width >= 0)
8469         {
8470           for_width -= (info->margin.left + info->margin.right);
8471           if (for_width < 0)
8472             for_width = 0;
8473         }
8474
8475       klass = CLUTTER_ACTOR_GET_CLASS (self);
8476       klass->get_preferred_height (self, for_width,
8477                                    &minimum_height,
8478                                    &natural_height);
8479
8480       /* adjust for margin */
8481       minimum_height += (info->margin.top + info->margin.bottom);
8482       natural_height += (info->margin.top + info->margin.bottom);
8483
8484       /* Due to accumulated float errors, it's better not to warn
8485        * on this, but just fix it.
8486        */
8487       if (natural_height < minimum_height)
8488         natural_height = minimum_height;
8489
8490       cached_size_request->min_size = minimum_height;
8491       cached_size_request->natural_size = natural_height;
8492       cached_size_request->for_size = for_width;
8493       cached_size_request->age = priv->cached_height_age;
8494
8495       priv->cached_height_age += 1;
8496       priv->needs_height_request = FALSE;
8497     }
8498
8499   if (!priv->min_height_set)
8500     request_min_height = cached_size_request->min_size;
8501   else
8502     request_min_height = info->margin.top
8503                        + info->minimum.height
8504                        + info->margin.bottom;
8505
8506   if (!priv->natural_height_set)
8507     request_natural_height = cached_size_request->natural_size;
8508   else
8509     request_natural_height = info->margin.top
8510                            + info->natural.height
8511                            + info->margin.bottom;
8512
8513   if (min_height_p)
8514     *min_height_p = request_min_height;
8515
8516   if (natural_height_p)
8517     *natural_height_p = request_natural_height;
8518 }
8519
8520 /**
8521  * clutter_actor_get_allocation_box:
8522  * @self: A #ClutterActor
8523  * @box: (out): the function fills this in with the actor's allocation
8524  *
8525  * Gets the layout box an actor has been assigned. The allocation can
8526  * only be assumed valid inside a paint() method; anywhere else, it
8527  * may be out-of-date.
8528  *
8529  * An allocation does not incorporate the actor's scale or anchor point;
8530  * those transformations do not affect layout, only rendering.
8531  *
8532  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8533  * of functions inside the implementation of the get_preferred_width()
8534  * or get_preferred_height() virtual functions.</note>
8535  *
8536  * Since: 0.8
8537  */
8538 void
8539 clutter_actor_get_allocation_box (ClutterActor    *self,
8540                                   ClutterActorBox *box)
8541 {
8542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8543
8544   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8545    * which limits calling get_allocation to inside paint() basically; or
8546    * we can 2) force a layout, which could be expensive if someone calls
8547    * get_allocation somewhere silly; or we can 3) just return the latest
8548    * value, allowing it to be out-of-date, and assume people know what
8549    * they are doing.
8550    *
8551    * The least-surprises approach that keeps existing code working is
8552    * likely to be 2). People can end up doing some inefficient things,
8553    * though, and in general code that requires 2) is probably broken.
8554    */
8555
8556   /* this implements 2) */
8557   if (G_UNLIKELY (self->priv->needs_allocation))
8558     {
8559       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8560
8561       /* do not queue a relayout on an unparented actor */
8562       if (stage)
8563         _clutter_stage_maybe_relayout (stage);
8564     }
8565
8566   /* commenting out the code above and just keeping this assigment
8567    * implements 3)
8568    */
8569   *box = self->priv->allocation;
8570 }
8571
8572 /**
8573  * clutter_actor_get_allocation_geometry:
8574  * @self: A #ClutterActor
8575  * @geom: (out): allocation geometry in pixels
8576  *
8577  * Gets the layout box an actor has been assigned.  The allocation can
8578  * only be assumed valid inside a paint() method; anywhere else, it
8579  * may be out-of-date.
8580  *
8581  * An allocation does not incorporate the actor's scale or anchor point;
8582  * those transformations do not affect layout, only rendering.
8583  *
8584  * The returned rectangle is in pixels.
8585  *
8586  * Since: 0.8
8587  */
8588 void
8589 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8590                                        ClutterGeometry *geom)
8591 {
8592   ClutterActorBox box;
8593
8594   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8595   g_return_if_fail (geom != NULL);
8596
8597   clutter_actor_get_allocation_box (self, &box);
8598
8599   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8600   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8601   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8602   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8603 }
8604
8605 static void
8606 clutter_actor_update_constraints (ClutterActor    *self,
8607                                   ClutterActorBox *allocation)
8608 {
8609   ClutterActorPrivate *priv = self->priv;
8610   const GList *constraints, *l;
8611
8612   if (priv->constraints == NULL)
8613     return;
8614
8615   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8616   for (l = constraints; l != NULL; l = l->next)
8617     {
8618       ClutterConstraint *constraint = l->data;
8619       ClutterActorMeta *meta = l->data;
8620
8621       if (clutter_actor_meta_get_enabled (meta))
8622         {
8623           _clutter_constraint_update_allocation (constraint,
8624                                                  self,
8625                                                  allocation);
8626
8627           CLUTTER_NOTE (LAYOUT,
8628                         "Allocation of '%s' after constraint '%s': "
8629                         "{ %.2f, %.2f, %.2f, %.2f }",
8630                         _clutter_actor_get_debug_name (self),
8631                         _clutter_actor_meta_get_debug_name (meta),
8632                         allocation->x1,
8633                         allocation->y1,
8634                         allocation->x2,
8635                         allocation->y2);
8636         }
8637     }
8638 }
8639
8640 /*< private >
8641  * clutter_actor_adjust_allocation:
8642  * @self: a #ClutterActor
8643  * @allocation: (inout): the allocation to adjust
8644  *
8645  * Adjusts the passed allocation box taking into account the actor's
8646  * layout information, like alignment, expansion, and margin.
8647  */
8648 static void
8649 clutter_actor_adjust_allocation (ClutterActor    *self,
8650                                  ClutterActorBox *allocation)
8651 {
8652   ClutterActorBox adj_allocation;
8653   float alloc_width, alloc_height;
8654   float min_width, min_height;
8655   float nat_width, nat_height;
8656   ClutterRequestMode req_mode;
8657
8658   adj_allocation = *allocation;
8659
8660   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8661
8662   /* we want to hit the cache, so we use the public API */
8663   req_mode = clutter_actor_get_request_mode (self);
8664
8665   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8666     {
8667       clutter_actor_get_preferred_width (self, -1,
8668                                          &min_width,
8669                                          &nat_width);
8670       clutter_actor_get_preferred_height (self, alloc_width,
8671                                           &min_height,
8672                                           &nat_height);
8673     }
8674   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8675     {
8676       clutter_actor_get_preferred_height (self, -1,
8677                                           &min_height,
8678                                           &nat_height);
8679       clutter_actor_get_preferred_width (self, alloc_height,
8680                                          &min_width,
8681                                          &nat_width);
8682     }
8683
8684 #ifdef CLUTTER_ENABLE_DEBUG
8685   /* warn about underallocations */
8686   if (_clutter_diagnostic_enabled () &&
8687       (floorf (min_width - alloc_width) > 0 ||
8688        floorf (min_height - alloc_height) > 0))
8689     {
8690       ClutterActor *parent = clutter_actor_get_parent (self);
8691
8692       /* the only actors that are allowed to be underallocated are the Stage,
8693        * as it doesn't have an implicit size, and Actors that specifically
8694        * told us that they want to opt-out from layout control mechanisms
8695        * through the NO_LAYOUT escape hatch.
8696        */
8697       if (parent != NULL &&
8698           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8699         {
8700           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8701                      "of %.2f x %.2f from its parent actor '%s', but its "
8702                      "requested minimum size is of %.2f x %.2f",
8703                      _clutter_actor_get_debug_name (self),
8704                      alloc_width, alloc_height,
8705                      _clutter_actor_get_debug_name (parent),
8706                      min_width, min_height);
8707         }
8708     }
8709 #endif
8710
8711   clutter_actor_adjust_width (self,
8712                               &min_width,
8713                               &nat_width,
8714                               &adj_allocation.x1,
8715                               &adj_allocation.x2);
8716
8717   clutter_actor_adjust_height (self,
8718                                &min_height,
8719                                &nat_height,
8720                                &adj_allocation.y1,
8721                                &adj_allocation.y2);
8722
8723   /* we maintain the invariant that an allocation cannot be adjusted
8724    * to be outside the parent-given box
8725    */
8726   if (adj_allocation.x1 < allocation->x1 ||
8727       adj_allocation.y1 < allocation->y1 ||
8728       adj_allocation.x2 > allocation->x2 ||
8729       adj_allocation.y2 > allocation->y2)
8730     {
8731       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8732                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8733                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8734                  _clutter_actor_get_debug_name (self),
8735                  adj_allocation.x1, adj_allocation.y1,
8736                  adj_allocation.x2 - adj_allocation.x1,
8737                  adj_allocation.y2 - adj_allocation.y1,
8738                  allocation->x1, allocation->y1,
8739                  allocation->x2 - allocation->x1,
8740                  allocation->y2 - allocation->y1);
8741       return;
8742     }
8743
8744   *allocation = adj_allocation;
8745 }
8746
8747 static void
8748 clutter_actor_allocate_internal (ClutterActor           *self,
8749                                  const ClutterActorBox  *allocation,
8750                                  ClutterAllocationFlags  flags)
8751 {
8752   ClutterActorClass *klass;
8753
8754   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8755
8756   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8757                 _clutter_actor_get_debug_name (self));
8758
8759   klass = CLUTTER_ACTOR_GET_CLASS (self);
8760   klass->allocate (self, allocation, flags);
8761
8762   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8763
8764   clutter_actor_queue_redraw (self);
8765 }
8766
8767 /**
8768  * clutter_actor_allocate:
8769  * @self: A #ClutterActor
8770  * @box: new allocation of the actor, in parent-relative coordinates
8771  * @flags: flags that control the allocation
8772  *
8773  * Called by the parent of an actor to assign the actor its size.
8774  * Should never be called by applications (except when implementing
8775  * a container or layout manager).
8776  *
8777  * Actors can know from their allocation box whether they have moved
8778  * with respect to their parent actor. The @flags parameter describes
8779  * additional information about the allocation, for instance whether
8780  * the parent has moved with respect to the stage, for example because
8781  * a grandparent's origin has moved.
8782  *
8783  * Since: 0.8
8784  */
8785 void
8786 clutter_actor_allocate (ClutterActor           *self,
8787                         const ClutterActorBox  *box,
8788                         ClutterAllocationFlags  flags)
8789 {
8790   ClutterActorBox old_allocation, real_allocation;
8791   gboolean origin_changed, child_moved, size_changed;
8792   gboolean stage_allocation_changed;
8793   ClutterActorPrivate *priv;
8794
8795   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8797     {
8798       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8799                  "which isn't a descendent of the stage!\n",
8800                  self, _clutter_actor_get_debug_name (self));
8801       return;
8802     }
8803
8804   priv = self->priv;
8805
8806   old_allocation = priv->allocation;
8807   real_allocation = *box;
8808
8809   /* constraints are allowed to modify the allocation only here; we do
8810    * this prior to all the other checks so that we can bail out if the
8811    * allocation did not change
8812    */
8813   clutter_actor_update_constraints (self, &real_allocation);
8814
8815   /* adjust the allocation depending on the align/margin properties */
8816   clutter_actor_adjust_allocation (self, &real_allocation);
8817
8818   if (real_allocation.x2 < real_allocation.x1 ||
8819       real_allocation.y2 < real_allocation.y1)
8820     {
8821       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8822                  _clutter_actor_get_debug_name (self),
8823                  real_allocation.x2 - real_allocation.x1,
8824                  real_allocation.y2 - real_allocation.y1);
8825     }
8826
8827   /* we allow 0-sized actors, but not negative-sized ones */
8828   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8829   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8830
8831   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8832
8833   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8834                  real_allocation.y1 != old_allocation.y1);
8835
8836   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8837                   real_allocation.y2 != old_allocation.y2);
8838
8839   if (origin_changed || child_moved || size_changed)
8840     stage_allocation_changed = TRUE;
8841   else
8842     stage_allocation_changed = FALSE;
8843
8844   /* If we get an allocation "out of the blue"
8845    * (we did not queue relayout), then we want to
8846    * ignore it. But if we have needs_allocation set,
8847    * we want to guarantee that allocate() virtual
8848    * method is always called, i.e. that queue_relayout()
8849    * always results in an allocate() invocation on
8850    * an actor.
8851    *
8852    * The optimization here is to avoid re-allocating
8853    * actors that did not queue relayout and were
8854    * not moved.
8855    */
8856   if (!priv->needs_allocation && !stage_allocation_changed)
8857     {
8858       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8859       return;
8860     }
8861
8862   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8863    * clutter_actor_allocate(), it indicates whether the parent has its
8864    * absolute origin moved; when passed in to ClutterActor::allocate()
8865    * virtual method though, it indicates whether the child has its
8866    * absolute origin moved.  So we set it when child_moved is TRUE
8867    */
8868   if (child_moved)
8869     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8870
8871   /* store the flags here, so that they can be propagated by the
8872    * transition code
8873    */
8874   self->priv->allocation_flags = flags;
8875
8876   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8877     {
8878       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8879                                         &priv->allocation,
8880                                         &real_allocation);
8881     }
8882   else
8883     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8884                                       &real_allocation);
8885 }
8886
8887 /**
8888  * clutter_actor_set_allocation:
8889  * @self: a #ClutterActor
8890  * @box: a #ClutterActorBox
8891  * @flags: allocation flags
8892  *
8893  * Stores the allocation of @self as defined by @box.
8894  *
8895  * This function can only be called from within the implementation of
8896  * the #ClutterActorClass.allocate() virtual function.
8897  *
8898  * The allocation should have been adjusted to take into account constraints,
8899  * alignment, and margin properties. If you are implementing a #ClutterActor
8900  * subclass that provides its own layout management policy for its children
8901  * instead of using a #ClutterLayoutManager delegate, you should not call
8902  * this function on the children of @self; instead, you should call
8903  * clutter_actor_allocate(), which will adjust the allocation box for
8904  * you.
8905  *
8906  * This function should only be used by subclasses of #ClutterActor
8907  * that wish to store their allocation but cannot chain up to the
8908  * parent's implementation; the default implementation of the
8909  * #ClutterActorClass.allocate() virtual function will call this
8910  * function.
8911  *
8912  * It is important to note that, while chaining up was the recommended
8913  * behaviour for #ClutterActor subclasses prior to the introduction of
8914  * this function, it is recommended to call clutter_actor_set_allocation()
8915  * instead.
8916  *
8917  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8918  * to handle the allocation of its children, this function will call
8919  * the clutter_layout_manager_allocate() function only if the
8920  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8921  * expected that the subclass will call clutter_layout_manager_allocate()
8922  * by itself. For instance, the following code:
8923  *
8924  * |[
8925  * static void
8926  * my_actor_allocate (ClutterActor *actor,
8927  *                    const ClutterActorBox *allocation,
8928  *                    ClutterAllocationFlags flags)
8929  * {
8930  *   ClutterActorBox new_alloc;
8931  *   ClutterAllocationFlags new_flags;
8932  *
8933  *   adjust_allocation (allocation, &amp;new_alloc);
8934  *
8935  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8936  *
8937  *   /&ast; this will use the layout manager set on the actor &ast;/
8938  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8939  * }
8940  * ]|
8941  *
8942  * is equivalent to this:
8943  *
8944  * |[
8945  * static void
8946  * my_actor_allocate (ClutterActor *actor,
8947  *                    const ClutterActorBox *allocation,
8948  *                    ClutterAllocationFlags flags)
8949  * {
8950  *   ClutterLayoutManager *layout;
8951  *   ClutterActorBox new_alloc;
8952  *
8953  *   adjust_allocation (allocation, &amp;new_alloc);
8954  *
8955  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8956  *
8957  *   layout = clutter_actor_get_layout_manager (actor);
8958  *   clutter_layout_manager_allocate (layout,
8959  *                                    CLUTTER_CONTAINER (actor),
8960  *                                    &amp;new_alloc,
8961  *                                    flags);
8962  * }
8963  * ]|
8964  *
8965  * Since: 1.10
8966  */
8967 void
8968 clutter_actor_set_allocation (ClutterActor           *self,
8969                               const ClutterActorBox  *box,
8970                               ClutterAllocationFlags  flags)
8971 {
8972   ClutterActorPrivate *priv;
8973   gboolean changed;
8974
8975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8976   g_return_if_fail (box != NULL);
8977
8978   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8979     {
8980       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8981                   "can only be called from within the implementation of "
8982                   "the ClutterActor::allocate() virtual function.");
8983       return;
8984     }
8985
8986   priv = self->priv;
8987
8988   g_object_freeze_notify (G_OBJECT (self));
8989
8990   changed = clutter_actor_set_allocation_internal (self, box, flags);
8991
8992   /* we allocate our children before we notify changes in our geometry,
8993    * so that people connecting to properties will be able to get valid
8994    * data out of the sub-tree of the scene graph that has this actor at
8995    * the root.
8996    */
8997   clutter_actor_maybe_layout_children (self, box, flags);
8998
8999   if (changed)
9000     {
9001       ClutterActorBox signal_box = priv->allocation;
9002       ClutterAllocationFlags signal_flags = priv->allocation_flags;
9003
9004       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
9005                      &signal_box,
9006                      signal_flags);
9007     }
9008
9009   g_object_thaw_notify (G_OBJECT (self));
9010 }
9011
9012 /**
9013  * clutter_actor_set_geometry:
9014  * @self: A #ClutterActor
9015  * @geometry: A #ClutterGeometry
9016  *
9017  * Sets the actor's fixed position and forces its minimum and natural
9018  * size, in pixels. This means the untransformed actor will have the
9019  * given geometry. This is the same as calling clutter_actor_set_position()
9020  * and clutter_actor_set_size().
9021  *
9022  * Deprecated: 1.10: Use clutter_actor_set_position() and
9023  *   clutter_actor_set_size() instead.
9024  */
9025 void
9026 clutter_actor_set_geometry (ClutterActor          *self,
9027                             const ClutterGeometry *geometry)
9028 {
9029   g_object_freeze_notify (G_OBJECT (self));
9030
9031   clutter_actor_set_position (self, geometry->x, geometry->y);
9032   clutter_actor_set_size (self, geometry->width, geometry->height);
9033
9034   g_object_thaw_notify (G_OBJECT (self));
9035 }
9036
9037 /**
9038  * clutter_actor_get_geometry:
9039  * @self: A #ClutterActor
9040  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9041  *
9042  * Gets the size and position of an actor relative to its parent
9043  * actor. This is the same as calling clutter_actor_get_position() and
9044  * clutter_actor_get_size(). It tries to "do what you mean" and get the
9045  * requested size and position if the actor's allocation is invalid.
9046  *
9047  * Deprecated: 1.10: Use clutter_actor_get_position() and
9048  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9049  *   instead.
9050  */
9051 void
9052 clutter_actor_get_geometry (ClutterActor    *self,
9053                             ClutterGeometry *geometry)
9054 {
9055   gfloat x, y, width, height;
9056
9057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9058   g_return_if_fail (geometry != NULL);
9059
9060   clutter_actor_get_position (self, &x, &y);
9061   clutter_actor_get_size (self, &width, &height);
9062
9063   geometry->x = (int) x;
9064   geometry->y = (int) y;
9065   geometry->width = (int) width;
9066   geometry->height = (int) height;
9067 }
9068
9069 /**
9070  * clutter_actor_set_position:
9071  * @self: A #ClutterActor
9072  * @x: New left position of actor in pixels.
9073  * @y: New top position of actor in pixels.
9074  *
9075  * Sets the actor's fixed position in pixels relative to any parent
9076  * actor.
9077  *
9078  * If a layout manager is in use, this position will override the
9079  * layout manager and force a fixed position.
9080  */
9081 void
9082 clutter_actor_set_position (ClutterActor *self,
9083                             gfloat        x,
9084                             gfloat        y)
9085 {
9086   ClutterPoint new_position;
9087
9088   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9089
9090   clutter_point_init (&new_position, x, y);
9091
9092   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9093     {
9094       ClutterPoint cur_position;
9095
9096       cur_position.x = clutter_actor_get_x (self);
9097       cur_position.y = clutter_actor_get_y (self);
9098
9099       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9100                                         &cur_position,
9101                                         &new_position);
9102     }
9103   else
9104     _clutter_actor_update_transition (self,
9105                                       obj_props[PROP_POSITION],
9106                                       &new_position);
9107
9108   clutter_actor_queue_relayout (self);
9109 }
9110
9111 /**
9112  * clutter_actor_get_fixed_position_set:
9113  * @self: A #ClutterActor
9114  *
9115  * Checks whether an actor has a fixed position set (and will thus be
9116  * unaffected by any layout manager).
9117  *
9118  * Return value: %TRUE if the fixed position is set on the actor
9119  *
9120  * Since: 0.8
9121  */
9122 gboolean
9123 clutter_actor_get_fixed_position_set (ClutterActor *self)
9124 {
9125   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9126
9127   return self->priv->position_set;
9128 }
9129
9130 /**
9131  * clutter_actor_set_fixed_position_set:
9132  * @self: A #ClutterActor
9133  * @is_set: whether to use fixed position
9134  *
9135  * Sets whether an actor has a fixed position set (and will thus be
9136  * unaffected by any layout manager).
9137  *
9138  * Since: 0.8
9139  */
9140 void
9141 clutter_actor_set_fixed_position_set (ClutterActor *self,
9142                                       gboolean      is_set)
9143 {
9144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9145
9146   if (self->priv->position_set == (is_set != FALSE))
9147     return;
9148
9149   if (!is_set)
9150     {
9151       ClutterLayoutInfo *info;
9152
9153       /* Ensure we set back the default fixed position of 0,0 so that setting
9154          just one of x/y always atomically gets 0 for the other */
9155       info = _clutter_actor_peek_layout_info (self);
9156       if (info != NULL)
9157         {
9158           info->fixed_pos.x = 0;
9159           info->fixed_pos.y = 0;
9160         }
9161     }
9162
9163   self->priv->position_set = is_set != FALSE;
9164   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9165
9166   clutter_actor_queue_relayout (self);
9167 }
9168
9169 /**
9170  * clutter_actor_move_by:
9171  * @self: A #ClutterActor
9172  * @dx: Distance to move Actor on X axis.
9173  * @dy: Distance to move Actor on Y axis.
9174  *
9175  * Moves an actor by the specified distance relative to its current
9176  * position in pixels.
9177  *
9178  * This function modifies the fixed position of an actor and thus removes
9179  * it from any layout management. Another way to move an actor is with an
9180  * anchor point, see clutter_actor_set_anchor_point().
9181  *
9182  * Since: 0.2
9183  */
9184 void
9185 clutter_actor_move_by (ClutterActor *self,
9186                        gfloat        dx,
9187                        gfloat        dy)
9188 {
9189   const ClutterLayoutInfo *info;
9190   gfloat x, y;
9191
9192   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9193
9194   info = _clutter_actor_get_layout_info_or_defaults (self);
9195   x = info->fixed_pos.x;
9196   y = info->fixed_pos.y;
9197
9198   clutter_actor_set_position (self, x + dx, y + dy);
9199 }
9200
9201 static void
9202 clutter_actor_set_min_width (ClutterActor *self,
9203                              gfloat        min_width)
9204 {
9205   ClutterActorPrivate *priv = self->priv;
9206   ClutterActorBox old = { 0, };
9207   ClutterLayoutInfo *info;
9208
9209   /* if we are setting the size on a top-level actor and the
9210    * backend only supports static top-levels (e.g. framebuffers)
9211    * then we ignore the passed value and we override it with
9212    * the stage implementation's preferred size.
9213    */
9214   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9215       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9216     return;
9217
9218   info = _clutter_actor_get_layout_info (self);
9219
9220   if (priv->min_width_set && min_width == info->minimum.width)
9221     return;
9222
9223   g_object_freeze_notify (G_OBJECT (self));
9224
9225   clutter_actor_store_old_geometry (self, &old);
9226
9227   info->minimum.width = min_width;
9228   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9229   clutter_actor_set_min_width_set (self, TRUE);
9230
9231   clutter_actor_notify_if_geometry_changed (self, &old);
9232
9233   g_object_thaw_notify (G_OBJECT (self));
9234
9235   clutter_actor_queue_relayout (self);
9236 }
9237
9238 static void
9239 clutter_actor_set_min_height (ClutterActor *self,
9240                               gfloat        min_height)
9241
9242 {
9243   ClutterActorPrivate *priv = self->priv;
9244   ClutterActorBox old = { 0, };
9245   ClutterLayoutInfo *info;
9246
9247   /* if we are setting the size on a top-level actor and the
9248    * backend only supports static top-levels (e.g. framebuffers)
9249    * then we ignore the passed value and we override it with
9250    * the stage implementation's preferred size.
9251    */
9252   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9253       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9254     return;
9255
9256   info = _clutter_actor_get_layout_info (self);
9257
9258   if (priv->min_height_set && min_height == info->minimum.height)
9259     return;
9260
9261   g_object_freeze_notify (G_OBJECT (self));
9262
9263   clutter_actor_store_old_geometry (self, &old);
9264
9265   info->minimum.height = min_height;
9266   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9267   clutter_actor_set_min_height_set (self, TRUE);
9268
9269   clutter_actor_notify_if_geometry_changed (self, &old);
9270
9271   g_object_thaw_notify (G_OBJECT (self));
9272
9273   clutter_actor_queue_relayout (self);
9274 }
9275
9276 static void
9277 clutter_actor_set_natural_width (ClutterActor *self,
9278                                  gfloat        natural_width)
9279 {
9280   ClutterActorPrivate *priv = self->priv;
9281   ClutterActorBox old = { 0, };
9282   ClutterLayoutInfo *info;
9283
9284   /* if we are setting the size on a top-level actor and the
9285    * backend only supports static top-levels (e.g. framebuffers)
9286    * then we ignore the passed value and we override it with
9287    * the stage implementation's preferred size.
9288    */
9289   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9290       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9291     return;
9292
9293   info = _clutter_actor_get_layout_info (self);
9294
9295   if (priv->natural_width_set && natural_width == info->natural.width)
9296     return;
9297
9298   g_object_freeze_notify (G_OBJECT (self));
9299
9300   clutter_actor_store_old_geometry (self, &old);
9301
9302   info->natural.width = natural_width;
9303   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9304   clutter_actor_set_natural_width_set (self, TRUE);
9305
9306   clutter_actor_notify_if_geometry_changed (self, &old);
9307
9308   g_object_thaw_notify (G_OBJECT (self));
9309
9310   clutter_actor_queue_relayout (self);
9311 }
9312
9313 static void
9314 clutter_actor_set_natural_height (ClutterActor *self,
9315                                   gfloat        natural_height)
9316 {
9317   ClutterActorPrivate *priv = self->priv;
9318   ClutterActorBox old = { 0, };
9319   ClutterLayoutInfo *info;
9320
9321   /* if we are setting the size on a top-level actor and the
9322    * backend only supports static top-levels (e.g. framebuffers)
9323    * then we ignore the passed value and we override it with
9324    * the stage implementation's preferred size.
9325    */
9326   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9327       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9328     return;
9329
9330   info = _clutter_actor_get_layout_info (self);
9331
9332   if (priv->natural_height_set && natural_height == info->natural.height)
9333     return;
9334
9335   g_object_freeze_notify (G_OBJECT (self));
9336
9337   clutter_actor_store_old_geometry (self, &old);
9338
9339   info->natural.height = natural_height;
9340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9341   clutter_actor_set_natural_height_set (self, TRUE);
9342
9343   clutter_actor_notify_if_geometry_changed (self, &old);
9344
9345   g_object_thaw_notify (G_OBJECT (self));
9346
9347   clutter_actor_queue_relayout (self);
9348 }
9349
9350 static void
9351 clutter_actor_set_min_width_set (ClutterActor *self,
9352                                  gboolean      use_min_width)
9353 {
9354   ClutterActorPrivate *priv = self->priv;
9355   ClutterActorBox old = { 0, };
9356
9357   if (priv->min_width_set == (use_min_width != FALSE))
9358     return;
9359
9360   clutter_actor_store_old_geometry (self, &old);
9361
9362   priv->min_width_set = use_min_width != FALSE;
9363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9364
9365   clutter_actor_notify_if_geometry_changed (self, &old);
9366
9367   clutter_actor_queue_relayout (self);
9368 }
9369
9370 static void
9371 clutter_actor_set_min_height_set (ClutterActor *self,
9372                                   gboolean      use_min_height)
9373 {
9374   ClutterActorPrivate *priv = self->priv;
9375   ClutterActorBox old = { 0, };
9376
9377   if (priv->min_height_set == (use_min_height != FALSE))
9378     return;
9379
9380   clutter_actor_store_old_geometry (self, &old);
9381
9382   priv->min_height_set = use_min_height != FALSE;
9383   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9384
9385   clutter_actor_notify_if_geometry_changed (self, &old);
9386
9387   clutter_actor_queue_relayout (self);
9388 }
9389
9390 static void
9391 clutter_actor_set_natural_width_set (ClutterActor *self,
9392                                      gboolean      use_natural_width)
9393 {
9394   ClutterActorPrivate *priv = self->priv;
9395   ClutterActorBox old = { 0, };
9396
9397   if (priv->natural_width_set == (use_natural_width != FALSE))
9398     return;
9399
9400   clutter_actor_store_old_geometry (self, &old);
9401
9402   priv->natural_width_set = use_natural_width != FALSE;
9403   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9404
9405   clutter_actor_notify_if_geometry_changed (self, &old);
9406
9407   clutter_actor_queue_relayout (self);
9408 }
9409
9410 static void
9411 clutter_actor_set_natural_height_set (ClutterActor *self,
9412                                       gboolean      use_natural_height)
9413 {
9414   ClutterActorPrivate *priv = self->priv;
9415   ClutterActorBox old = { 0, };
9416
9417   if (priv->natural_height_set == (use_natural_height != FALSE))
9418     return;
9419
9420   clutter_actor_store_old_geometry (self, &old);
9421
9422   priv->natural_height_set = use_natural_height != FALSE;
9423   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9424
9425   clutter_actor_notify_if_geometry_changed (self, &old);
9426
9427   clutter_actor_queue_relayout (self);
9428 }
9429
9430 /**
9431  * clutter_actor_set_request_mode:
9432  * @self: a #ClutterActor
9433  * @mode: the request mode
9434  *
9435  * Sets the geometry request mode of @self.
9436  *
9437  * The @mode determines the order for invoking
9438  * clutter_actor_get_preferred_width() and
9439  * clutter_actor_get_preferred_height()
9440  *
9441  * Since: 1.2
9442  */
9443 void
9444 clutter_actor_set_request_mode (ClutterActor       *self,
9445                                 ClutterRequestMode  mode)
9446 {
9447   ClutterActorPrivate *priv;
9448
9449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9450
9451   priv = self->priv;
9452
9453   if (priv->request_mode == mode)
9454     return;
9455
9456   priv->request_mode = mode;
9457
9458   priv->needs_width_request = TRUE;
9459   priv->needs_height_request = TRUE;
9460
9461   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9462
9463   clutter_actor_queue_relayout (self);
9464 }
9465
9466 /**
9467  * clutter_actor_get_request_mode:
9468  * @self: a #ClutterActor
9469  *
9470  * Retrieves the geometry request mode of @self
9471  *
9472  * Return value: the request mode for the actor
9473  *
9474  * Since: 1.2
9475  */
9476 ClutterRequestMode
9477 clutter_actor_get_request_mode (ClutterActor *self)
9478 {
9479   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9480                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9481
9482   return self->priv->request_mode;
9483 }
9484
9485 /* variant of set_width() without checks and without notification
9486  * freeze+thaw, for internal usage only
9487  */
9488 static inline void
9489 clutter_actor_set_width_internal (ClutterActor *self,
9490                                   gfloat        width)
9491 {
9492   if (width >= 0)
9493     {
9494       /* the Stage will use the :min-width to control the minimum
9495        * width to be resized to, so we should not be setting it
9496        * along with the :natural-width
9497        */
9498       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9499         clutter_actor_set_min_width (self, width);
9500
9501       clutter_actor_set_natural_width (self, width);
9502     }
9503   else
9504     {
9505       /* we only unset the :natural-width for the Stage */
9506       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9507         clutter_actor_set_min_width_set (self, FALSE);
9508
9509       clutter_actor_set_natural_width_set (self, FALSE);
9510     }
9511 }
9512
9513 /* variant of set_height() without checks and without notification
9514  * freeze+thaw, for internal usage only
9515  */
9516 static inline void
9517 clutter_actor_set_height_internal (ClutterActor *self,
9518                                    gfloat        height)
9519 {
9520   if (height >= 0)
9521     {
9522       /* see the comment above in set_width_internal() */
9523       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9524         clutter_actor_set_min_height (self, height);
9525
9526       clutter_actor_set_natural_height (self, height);
9527     }
9528   else
9529     {
9530       /* see the comment above in set_width_internal() */
9531       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9532         clutter_actor_set_min_height_set (self, FALSE);
9533
9534       clutter_actor_set_natural_height_set (self, FALSE);
9535     }
9536 }
9537
9538 static void
9539 clutter_actor_set_size_internal (ClutterActor      *self,
9540                                  const ClutterSize *size)
9541 {
9542   if (size != NULL)
9543     {
9544       clutter_actor_set_width_internal (self, size->width);
9545       clutter_actor_set_height_internal (self, size->height);
9546     }
9547   else
9548     {
9549       clutter_actor_set_width_internal (self, -1);
9550       clutter_actor_set_height_internal (self, -1);
9551     }
9552 }
9553
9554 /**
9555  * clutter_actor_set_size:
9556  * @self: A #ClutterActor
9557  * @width: New width of actor in pixels, or -1
9558  * @height: New height of actor in pixels, or -1
9559  *
9560  * Sets the actor's size request in pixels. This overrides any
9561  * "normal" size request the actor would have. For example
9562  * a text actor might normally request the size of the text;
9563  * this function would force a specific size instead.
9564  *
9565  * If @width and/or @height are -1 the actor will use its
9566  * "normal" size request instead of overriding it, i.e.
9567  * you can "unset" the size with -1.
9568  *
9569  * This function sets or unsets both the minimum and natural size.
9570  */
9571 void
9572 clutter_actor_set_size (ClutterActor *self,
9573                         gfloat        width,
9574                         gfloat        height)
9575 {
9576   ClutterSize new_size;
9577
9578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9579
9580   clutter_size_init (&new_size, width, height);
9581
9582   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9583     {
9584       /* minor optimization: if we don't have a duration then we can
9585        * skip the get_size() below, to avoid the chance of going through
9586        * get_preferred_width() and get_preferred_height() just to jump to
9587        * a new desired size
9588        */
9589       if (clutter_actor_get_easing_duration (self) == 0)
9590         {
9591           g_object_freeze_notify (G_OBJECT (self));
9592
9593           clutter_actor_set_size_internal (self, &new_size);
9594
9595           g_object_thaw_notify (G_OBJECT (self));
9596
9597           return;
9598         }
9599       else
9600         {
9601           ClutterSize cur_size;
9602
9603           clutter_size_init (&cur_size,
9604                              clutter_actor_get_width (self),
9605                              clutter_actor_get_height (self));
9606
9607          _clutter_actor_create_transition (self,
9608                                            obj_props[PROP_SIZE],
9609                                            &cur_size,
9610                                            &new_size);
9611         }
9612     }
9613   else
9614     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9615
9616   clutter_actor_queue_relayout (self);
9617 }
9618
9619 /**
9620  * clutter_actor_get_size:
9621  * @self: A #ClutterActor
9622  * @width: (out) (allow-none): return location for the width, or %NULL.
9623  * @height: (out) (allow-none): return location for the height, or %NULL.
9624  *
9625  * This function tries to "do what you mean" and return
9626  * the size an actor will have. If the actor has a valid
9627  * allocation, the allocation will be returned; otherwise,
9628  * the actors natural size request will be returned.
9629  *
9630  * If you care whether you get the request vs. the allocation, you
9631  * should probably call a different function like
9632  * clutter_actor_get_allocation_box() or
9633  * clutter_actor_get_preferred_width().
9634  *
9635  * Since: 0.2
9636  */
9637 void
9638 clutter_actor_get_size (ClutterActor *self,
9639                         gfloat       *width,
9640                         gfloat       *height)
9641 {
9642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9643
9644   if (width)
9645     *width = clutter_actor_get_width (self);
9646
9647   if (height)
9648     *height = clutter_actor_get_height (self);
9649 }
9650
9651 /**
9652  * clutter_actor_get_position:
9653  * @self: a #ClutterActor
9654  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9655  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9656  *
9657  * This function tries to "do what you mean" and tell you where the
9658  * actor is, prior to any transformations. Retrieves the fixed
9659  * position of an actor in pixels, if one has been set; otherwise, if
9660  * the allocation is valid, returns the actor's allocated position;
9661  * otherwise, returns 0,0.
9662  *
9663  * The returned position is in pixels.
9664  *
9665  * Since: 0.6
9666  */
9667 void
9668 clutter_actor_get_position (ClutterActor *self,
9669                             gfloat       *x,
9670                             gfloat       *y)
9671 {
9672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9673
9674   if (x)
9675     *x = clutter_actor_get_x (self);
9676
9677   if (y)
9678     *y = clutter_actor_get_y (self);
9679 }
9680
9681 /**
9682  * clutter_actor_get_transformed_position:
9683  * @self: A #ClutterActor
9684  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9685  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9686  *
9687  * Gets the absolute position of an actor, in pixels relative to the stage.
9688  *
9689  * Since: 0.8
9690  */
9691 void
9692 clutter_actor_get_transformed_position (ClutterActor *self,
9693                                         gfloat       *x,
9694                                         gfloat       *y)
9695 {
9696   ClutterVertex v1;
9697   ClutterVertex v2;
9698
9699   v1.x = v1.y = v1.z = 0;
9700   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9701
9702   if (x)
9703     *x = v2.x;
9704
9705   if (y)
9706     *y = v2.y;
9707 }
9708
9709 /**
9710  * clutter_actor_get_transformed_size:
9711  * @self: A #ClutterActor
9712  * @width: (out) (allow-none): return location for the width, or %NULL
9713  * @height: (out) (allow-none): return location for the height, or %NULL
9714  *
9715  * Gets the absolute size of an actor in pixels, taking into account the
9716  * scaling factors.
9717  *
9718  * If the actor has a valid allocation, the allocated size will be used.
9719  * If the actor has not a valid allocation then the preferred size will
9720  * be transformed and returned.
9721  *
9722  * If you want the transformed allocation, see
9723  * clutter_actor_get_abs_allocation_vertices() instead.
9724  *
9725  * <note>When the actor (or one of its ancestors) is rotated around the
9726  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9727  * as a generic quadrangle; in that case this function returns the size
9728  * of the smallest rectangle that encapsulates the entire quad. Please
9729  * note that in this case no assumptions can be made about the relative
9730  * position of this envelope to the absolute position of the actor, as
9731  * returned by clutter_actor_get_transformed_position(); if you need this
9732  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9733  * to get the coords of the actual quadrangle.</note>
9734  *
9735  * Since: 0.8
9736  */
9737 void
9738 clutter_actor_get_transformed_size (ClutterActor *self,
9739                                     gfloat       *width,
9740                                     gfloat       *height)
9741 {
9742   ClutterActorPrivate *priv;
9743   ClutterVertex v[4];
9744   gfloat x_min, x_max, y_min, y_max;
9745   gint i;
9746
9747   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9748
9749   priv = self->priv;
9750
9751   /* if the actor hasn't been allocated yet, get the preferred
9752    * size and transform that
9753    */
9754   if (priv->needs_allocation)
9755     {
9756       gfloat natural_width, natural_height;
9757       ClutterActorBox box;
9758
9759       /* Make a fake allocation to transform.
9760        *
9761        * NB: _clutter_actor_transform_and_project_box expects a box in
9762        * the actor's coordinate space... */
9763
9764       box.x1 = 0;
9765       box.y1 = 0;
9766
9767       natural_width = natural_height = 0;
9768       clutter_actor_get_preferred_size (self, NULL, NULL,
9769                                         &natural_width,
9770                                         &natural_height);
9771
9772       box.x2 = natural_width;
9773       box.y2 = natural_height;
9774
9775       _clutter_actor_transform_and_project_box (self, &box, v);
9776     }
9777   else
9778     clutter_actor_get_abs_allocation_vertices (self, v);
9779
9780   x_min = x_max = v[0].x;
9781   y_min = y_max = v[0].y;
9782
9783   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9784     {
9785       if (v[i].x < x_min)
9786         x_min = v[i].x;
9787
9788       if (v[i].x > x_max)
9789         x_max = v[i].x;
9790
9791       if (v[i].y < y_min)
9792         y_min = v[i].y;
9793
9794       if (v[i].y > y_max)
9795         y_max = v[i].y;
9796     }
9797
9798   if (width)
9799     *width  = x_max - x_min;
9800
9801   if (height)
9802     *height = y_max - y_min;
9803 }
9804
9805 /**
9806  * clutter_actor_get_width:
9807  * @self: A #ClutterActor
9808  *
9809  * Retrieves the width of a #ClutterActor.
9810  *
9811  * If the actor has a valid allocation, this function will return the
9812  * width of the allocated area given to the actor.
9813  *
9814  * If the actor does not have a valid allocation, this function will
9815  * return the actor's natural width, that is the preferred width of
9816  * the actor.
9817  *
9818  * If you care whether you get the preferred width or the width that
9819  * has been assigned to the actor, you should probably call a different
9820  * function like clutter_actor_get_allocation_box() to retrieve the
9821  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9822  * preferred width.
9823  *
9824  * If an actor has a fixed width, for instance a width that has been
9825  * assigned using clutter_actor_set_width(), the width returned will
9826  * be the same value.
9827  *
9828  * Return value: the width of the actor, in pixels
9829  */
9830 gfloat
9831 clutter_actor_get_width (ClutterActor *self)
9832 {
9833   ClutterActorPrivate *priv;
9834
9835   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9836
9837   priv = self->priv;
9838
9839   if (priv->needs_allocation)
9840     {
9841       gfloat natural_width = 0;
9842
9843       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9844         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9845       else
9846         {
9847           gfloat natural_height = 0;
9848
9849           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9850           clutter_actor_get_preferred_width (self, natural_height,
9851                                              NULL,
9852                                              &natural_width);
9853         }
9854
9855       return natural_width;
9856     }
9857   else
9858     return priv->allocation.x2 - priv->allocation.x1;
9859 }
9860
9861 /**
9862  * clutter_actor_get_height:
9863  * @self: A #ClutterActor
9864  *
9865  * Retrieves the height of a #ClutterActor.
9866  *
9867  * If the actor has a valid allocation, this function will return the
9868  * height of the allocated area given to the actor.
9869  *
9870  * If the actor does not have a valid allocation, this function will
9871  * return the actor's natural height, that is the preferred height of
9872  * the actor.
9873  *
9874  * If you care whether you get the preferred height or the height that
9875  * has been assigned to the actor, you should probably call a different
9876  * function like clutter_actor_get_allocation_box() to retrieve the
9877  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9878  * preferred height.
9879  *
9880  * If an actor has a fixed height, for instance a height that has been
9881  * assigned using clutter_actor_set_height(), the height returned will
9882  * be the same value.
9883  *
9884  * Return value: the height of the actor, in pixels
9885  */
9886 gfloat
9887 clutter_actor_get_height (ClutterActor *self)
9888 {
9889   ClutterActorPrivate *priv;
9890
9891   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9892
9893   priv = self->priv;
9894
9895   if (priv->needs_allocation)
9896     {
9897       gfloat natural_height = 0;
9898
9899       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9900         {
9901           gfloat natural_width = 0;
9902
9903           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9904           clutter_actor_get_preferred_height (self, natural_width,
9905                                               NULL, &natural_height);
9906         }
9907       else
9908         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9909
9910       return natural_height;
9911     }
9912   else
9913     return priv->allocation.y2 - priv->allocation.y1;
9914 }
9915
9916 /**
9917  * clutter_actor_set_width:
9918  * @self: A #ClutterActor
9919  * @width: Requested new width for the actor, in pixels, or -1
9920  *
9921  * Forces a width on an actor, causing the actor's preferred width
9922  * and height (if any) to be ignored.
9923  *
9924  * If @width is -1 the actor will use its preferred width request
9925  * instead of overriding it, i.e. you can "unset" the width with -1.
9926  *
9927  * This function sets both the minimum and natural size of the actor.
9928  *
9929  * since: 0.2
9930  */
9931 void
9932 clutter_actor_set_width (ClutterActor *self,
9933                          gfloat        width)
9934 {
9935   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9936
9937   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9938     {
9939       float cur_size;
9940
9941       /* minor optimization: if we don't have a duration
9942        * then we can skip the get_width() below, to avoid
9943        * the chance of going through get_preferred_width()
9944        * just to jump to a new desired width.
9945        */
9946       if (clutter_actor_get_easing_duration (self) == 0)
9947         {
9948           g_object_freeze_notify (G_OBJECT (self));
9949
9950           clutter_actor_set_width_internal (self, width);
9951
9952           g_object_thaw_notify (G_OBJECT (self));
9953
9954           return;
9955         }
9956       else
9957         cur_size = clutter_actor_get_width (self);
9958
9959       _clutter_actor_create_transition (self,
9960                                         obj_props[PROP_WIDTH],
9961                                         cur_size,
9962                                         width);
9963     }
9964   else
9965     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9966 }
9967
9968 /**
9969  * clutter_actor_set_height:
9970  * @self: A #ClutterActor
9971  * @height: Requested new height for the actor, in pixels, or -1
9972  *
9973  * Forces a height on an actor, causing the actor's preferred width
9974  * and height (if any) to be ignored.
9975  *
9976  * If @height is -1 the actor will use its preferred height instead of
9977  * overriding it, i.e. you can "unset" the height with -1.
9978  *
9979  * This function sets both the minimum and natural size of the actor.
9980  *
9981  * since: 0.2
9982  */
9983 void
9984 clutter_actor_set_height (ClutterActor *self,
9985                           gfloat        height)
9986 {
9987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9988
9989   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9990     {
9991       float cur_size;
9992
9993       /* see the comment in clutter_actor_set_width() above */
9994       if (clutter_actor_get_easing_duration (self) == 0)
9995         {
9996           g_object_freeze_notify (G_OBJECT (self));
9997
9998           clutter_actor_set_height_internal (self, height);
9999
10000           g_object_thaw_notify (G_OBJECT (self));
10001
10002           return;
10003         }
10004       else
10005         cur_size = clutter_actor_get_height (self);
10006
10007       _clutter_actor_create_transition (self,
10008                                         obj_props[PROP_HEIGHT],
10009                                         cur_size,
10010                                         height);
10011     }
10012   else
10013     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
10014 }
10015
10016 static inline void
10017 clutter_actor_set_x_internal (ClutterActor *self,
10018                               float         x)
10019 {
10020   ClutterActorPrivate *priv = self->priv;
10021   ClutterLayoutInfo *linfo;
10022   ClutterActorBox old = { 0, };
10023
10024   linfo = _clutter_actor_get_layout_info (self);
10025
10026   if (priv->position_set && linfo->fixed_pos.x == x)
10027     return;
10028
10029   clutter_actor_store_old_geometry (self, &old);
10030
10031   linfo->fixed_pos.x = x;
10032   clutter_actor_set_fixed_position_set (self, TRUE);
10033
10034   clutter_actor_notify_if_geometry_changed (self, &old);
10035
10036   clutter_actor_queue_relayout (self);
10037 }
10038
10039 static inline void
10040 clutter_actor_set_y_internal (ClutterActor *self,
10041                               float         y)
10042 {
10043   ClutterActorPrivate *priv = self->priv;
10044   ClutterLayoutInfo *linfo;
10045   ClutterActorBox old = { 0, };
10046
10047   linfo = _clutter_actor_get_layout_info (self);
10048
10049   if (priv->position_set && linfo->fixed_pos.y == y)
10050     return;
10051
10052   clutter_actor_store_old_geometry (self, &old);
10053
10054   linfo->fixed_pos.y = y;
10055   clutter_actor_set_fixed_position_set (self, TRUE);
10056
10057   clutter_actor_notify_if_geometry_changed (self, &old);
10058
10059   clutter_actor_queue_relayout (self);
10060 }
10061
10062 static void
10063 clutter_actor_set_position_internal (ClutterActor       *self,
10064                                      const ClutterPoint *position)
10065 {
10066   ClutterActorPrivate *priv = self->priv;
10067   ClutterLayoutInfo *linfo;
10068   ClutterActorBox old = { 0, };
10069
10070   linfo = _clutter_actor_get_layout_info (self);
10071
10072   if (priv->position_set &&
10073       clutter_point_equals (position, &linfo->fixed_pos))
10074     return;
10075
10076   clutter_actor_store_old_geometry (self, &old);
10077
10078   if (position != NULL)
10079     {
10080       linfo->fixed_pos = *position;
10081       clutter_actor_set_fixed_position_set (self, TRUE);
10082     }
10083   else
10084     clutter_actor_set_fixed_position_set (self, FALSE);
10085
10086   clutter_actor_notify_if_geometry_changed (self, &old);
10087
10088   clutter_actor_queue_relayout (self);
10089 }
10090
10091 /**
10092  * clutter_actor_set_x:
10093  * @self: a #ClutterActor
10094  * @x: the actor's position on the X axis
10095  *
10096  * Sets the actor's X coordinate, relative to its parent, in pixels.
10097  *
10098  * Overrides any layout manager and forces a fixed position for
10099  * the actor.
10100  *
10101  * The #ClutterActor:x property is animatable.
10102  *
10103  * Since: 0.6
10104  */
10105 void
10106 clutter_actor_set_x (ClutterActor *self,
10107                      gfloat        x)
10108 {
10109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10110
10111   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10112     {
10113       float cur_position = clutter_actor_get_x (self);
10114
10115       _clutter_actor_create_transition (self, obj_props[PROP_X],
10116                                         cur_position,
10117                                         x);
10118     }
10119   else
10120     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10121 }
10122
10123 /**
10124  * clutter_actor_set_y:
10125  * @self: a #ClutterActor
10126  * @y: the actor's position on the Y axis
10127  *
10128  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10129  *
10130  * Overrides any layout manager and forces a fixed position for
10131  * the actor.
10132  *
10133  * The #ClutterActor:y property is animatable.
10134  *
10135  * Since: 0.6
10136  */
10137 void
10138 clutter_actor_set_y (ClutterActor *self,
10139                      gfloat        y)
10140 {
10141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10142
10143   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10144     {
10145       float cur_position = clutter_actor_get_y (self);
10146
10147       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10148                                         cur_position,
10149                                         y);
10150     }
10151   else
10152     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10153 }
10154
10155 /**
10156  * clutter_actor_get_x:
10157  * @self: A #ClutterActor
10158  *
10159  * Retrieves the X coordinate of a #ClutterActor.
10160  *
10161  * This function tries to "do what you mean", by returning the
10162  * correct value depending on the actor's state.
10163  *
10164  * If the actor has a valid allocation, this function will return
10165  * the X coordinate of the origin of the allocation box.
10166  *
10167  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10168  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10169  * function will return that coordinate.
10170  *
10171  * If both the allocation and a fixed position are missing, this function
10172  * will return 0.
10173  *
10174  * Return value: the X coordinate, in pixels, ignoring any
10175  *   transformation (i.e. scaling, rotation)
10176  */
10177 gfloat
10178 clutter_actor_get_x (ClutterActor *self)
10179 {
10180   ClutterActorPrivate *priv;
10181
10182   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10183
10184   priv = self->priv;
10185
10186   if (priv->needs_allocation)
10187     {
10188       if (priv->position_set)
10189         {
10190           const ClutterLayoutInfo *info;
10191
10192           info = _clutter_actor_get_layout_info_or_defaults (self);
10193
10194           return info->fixed_pos.x;
10195         }
10196       else
10197         return 0;
10198     }
10199   else
10200     return priv->allocation.x1;
10201 }
10202
10203 /**
10204  * clutter_actor_get_y:
10205  * @self: A #ClutterActor
10206  *
10207  * Retrieves the Y coordinate of a #ClutterActor.
10208  *
10209  * This function tries to "do what you mean", by returning the
10210  * correct value depending on the actor's state.
10211  *
10212  * If the actor has a valid allocation, this function will return
10213  * the Y coordinate of the origin of the allocation box.
10214  *
10215  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10216  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10217  * function will return that coordinate.
10218  *
10219  * If both the allocation and a fixed position are missing, this function
10220  * will return 0.
10221  *
10222  * Return value: the Y coordinate, in pixels, ignoring any
10223  *   transformation (i.e. scaling, rotation)
10224  */
10225 gfloat
10226 clutter_actor_get_y (ClutterActor *self)
10227 {
10228   ClutterActorPrivate *priv;
10229
10230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10231
10232   priv = self->priv;
10233
10234   if (priv->needs_allocation)
10235     {
10236       if (priv->position_set)
10237         {
10238           const ClutterLayoutInfo *info;
10239
10240           info = _clutter_actor_get_layout_info_or_defaults (self);
10241
10242           return info->fixed_pos.y;
10243         }
10244       else
10245         return 0;
10246     }
10247   else
10248     return priv->allocation.y1;
10249 }
10250
10251 /**
10252  * clutter_actor_set_scale:
10253  * @self: A #ClutterActor
10254  * @scale_x: double factor to scale actor by horizontally.
10255  * @scale_y: double factor to scale actor by vertically.
10256  *
10257  * Scales an actor with the given factors. The scaling is relative to
10258  * the scale center and the anchor point. The scale center is
10259  * unchanged by this function and defaults to 0,0.
10260  *
10261  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10262  * animatable.
10263  *
10264  * Since: 0.2
10265  */
10266 void
10267 clutter_actor_set_scale (ClutterActor *self,
10268                          gdouble       scale_x,
10269                          gdouble       scale_y)
10270 {
10271   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10272
10273   g_object_freeze_notify (G_OBJECT (self));
10274
10275   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10276   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10277
10278   g_object_thaw_notify (G_OBJECT (self));
10279 }
10280
10281 /**
10282  * clutter_actor_set_scale_full:
10283  * @self: A #ClutterActor
10284  * @scale_x: double factor to scale actor by horizontally.
10285  * @scale_y: double factor to scale actor by vertically.
10286  * @center_x: X coordinate of the center of the scale.
10287  * @center_y: Y coordinate of the center of the scale
10288  *
10289  * Scales an actor with the given factors around the given center
10290  * point. The center point is specified in pixels relative to the
10291  * anchor point (usually the top left corner of the actor).
10292  *
10293  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10294  * are animatable.
10295  *
10296  * Since: 1.0
10297  */
10298 void
10299 clutter_actor_set_scale_full (ClutterActor *self,
10300                               gdouble       scale_x,
10301                               gdouble       scale_y,
10302                               gfloat        center_x,
10303                               gfloat        center_y)
10304 {
10305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10306
10307   g_object_freeze_notify (G_OBJECT (self));
10308
10309   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10310   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10311   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10312   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10313
10314   g_object_thaw_notify (G_OBJECT (self));
10315 }
10316
10317 /**
10318  * clutter_actor_set_scale_with_gravity:
10319  * @self: A #ClutterActor
10320  * @scale_x: double factor to scale actor by horizontally.
10321  * @scale_y: double factor to scale actor by vertically.
10322  * @gravity: the location of the scale center expressed as a compass
10323  * direction.
10324  *
10325  * Scales an actor with the given factors around the given
10326  * center point. The center point is specified as one of the compass
10327  * directions in #ClutterGravity. For example, setting it to north
10328  * will cause the top of the actor to remain unchanged and the rest of
10329  * the actor to expand left, right and downwards.
10330  *
10331  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10332  * animatable.
10333  *
10334  * Since: 1.0
10335  */
10336 void
10337 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10338                                       gdouble         scale_x,
10339                                       gdouble         scale_y,
10340                                       ClutterGravity  gravity)
10341 {
10342   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10343
10344   g_object_freeze_notify (G_OBJECT (self));
10345
10346   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10347   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10348   clutter_actor_set_scale_gravity (self, gravity);
10349
10350   g_object_thaw_notify (G_OBJECT (self));
10351 }
10352
10353 /**
10354  * clutter_actor_get_scale:
10355  * @self: A #ClutterActor
10356  * @scale_x: (out) (allow-none): Location to store horizonal
10357  *   scale factor, or %NULL.
10358  * @scale_y: (out) (allow-none): Location to store vertical
10359  *   scale factor, or %NULL.
10360  *
10361  * Retrieves an actors scale factors.
10362  *
10363  * Since: 0.2
10364  */
10365 void
10366 clutter_actor_get_scale (ClutterActor *self,
10367                          gdouble      *scale_x,
10368                          gdouble      *scale_y)
10369 {
10370   const ClutterTransformInfo *info;
10371
10372   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10373
10374   info = _clutter_actor_get_transform_info_or_defaults (self);
10375
10376   if (scale_x)
10377     *scale_x = info->scale_x;
10378
10379   if (scale_y)
10380     *scale_y = info->scale_y;
10381 }
10382
10383 /**
10384  * clutter_actor_get_scale_center:
10385  * @self: A #ClutterActor
10386  * @center_x: (out) (allow-none): Location to store the X position
10387  *   of the scale center, or %NULL.
10388  * @center_y: (out) (allow-none): Location to store the Y position
10389  *   of the scale center, or %NULL.
10390  *
10391  * Retrieves the scale center coordinate in pixels relative to the top
10392  * left corner of the actor. If the scale center was specified using a
10393  * #ClutterGravity this will calculate the pixel offset using the
10394  * current size of the actor.
10395  *
10396  * Since: 1.0
10397  */
10398 void
10399 clutter_actor_get_scale_center (ClutterActor *self,
10400                                 gfloat       *center_x,
10401                                 gfloat       *center_y)
10402 {
10403   const ClutterTransformInfo *info;
10404
10405   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10406
10407   info = _clutter_actor_get_transform_info_or_defaults (self);
10408
10409   clutter_anchor_coord_get_units (self, &info->scale_center,
10410                                   center_x,
10411                                   center_y,
10412                                   NULL);
10413 }
10414
10415 /**
10416  * clutter_actor_get_scale_gravity:
10417  * @self: A #ClutterActor
10418  *
10419  * Retrieves the scale center as a compass direction. If the scale
10420  * center was specified in pixels or units this will return
10421  * %CLUTTER_GRAVITY_NONE.
10422  *
10423  * Return value: the scale gravity
10424  *
10425  * Since: 1.0
10426  */
10427 ClutterGravity
10428 clutter_actor_get_scale_gravity (ClutterActor *self)
10429 {
10430   const ClutterTransformInfo *info;
10431
10432   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10433
10434   info = _clutter_actor_get_transform_info_or_defaults (self);
10435
10436   return clutter_anchor_coord_get_gravity (&info->scale_center);
10437 }
10438
10439 static inline void
10440 clutter_actor_set_opacity_internal (ClutterActor *self,
10441                                     guint8        opacity)
10442 {
10443   ClutterActorPrivate *priv = self->priv;
10444
10445   if (priv->opacity != opacity)
10446     {
10447       priv->opacity = opacity;
10448
10449       /* Queue a redraw from the flatten effect so that it can use
10450          its cached image if available instead of having to redraw the
10451          actual actor. If it doesn't end up using the FBO then the
10452          effect is still able to continue the paint anyway. If there
10453          is no flatten effect yet then this is equivalent to queueing
10454          a full redraw */
10455       _clutter_actor_queue_redraw_full (self,
10456                                         0, /* flags */
10457                                         NULL, /* clip */
10458                                         priv->flatten_effect);
10459
10460       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10461     }
10462 }
10463
10464 /**
10465  * clutter_actor_set_opacity:
10466  * @self: A #ClutterActor
10467  * @opacity: New opacity value for the actor.
10468  *
10469  * Sets the actor's opacity, with zero being completely transparent and
10470  * 255 (0xff) being fully opaque.
10471  *
10472  * The #ClutterActor:opacity property is animatable.
10473  */
10474 void
10475 clutter_actor_set_opacity (ClutterActor *self,
10476                            guint8        opacity)
10477 {
10478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10479
10480   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10481     {
10482       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10483                                         self->priv->opacity,
10484                                         opacity);
10485     }
10486   else
10487     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10488 }
10489
10490 /*
10491  * clutter_actor_get_paint_opacity_internal:
10492  * @self: a #ClutterActor
10493  *
10494  * Retrieves the absolute opacity of the actor, as it appears on the stage
10495  *
10496  * This function does not do type checks
10497  *
10498  * Return value: the absolute opacity of the actor
10499  */
10500 static guint8
10501 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10502 {
10503   ClutterActorPrivate *priv = self->priv;
10504   ClutterActor *parent;
10505
10506   /* override the top-level opacity to always be 255; even in
10507    * case of ClutterStage:use-alpha being TRUE we want the rest
10508    * of the scene to be painted
10509    */
10510   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10511     return 255;
10512
10513   if (priv->opacity_override >= 0)
10514     return priv->opacity_override;
10515
10516   parent = priv->parent;
10517
10518   /* Factor in the actual actors opacity with parents */
10519   if (parent != NULL)
10520     {
10521       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10522
10523       if (opacity != 0xff)
10524         return (opacity * priv->opacity) / 0xff;
10525     }
10526
10527   return priv->opacity;
10528
10529 }
10530
10531 /**
10532  * clutter_actor_get_paint_opacity:
10533  * @self: A #ClutterActor
10534  *
10535  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10536  *
10537  * This function traverses the hierarchy chain and composites the opacity of
10538  * the actor with that of its parents.
10539  *
10540  * This function is intended for subclasses to use in the paint virtual
10541  * function, to paint themselves with the correct opacity.
10542  *
10543  * Return value: The actor opacity value.
10544  *
10545  * Since: 0.8
10546  */
10547 guint8
10548 clutter_actor_get_paint_opacity (ClutterActor *self)
10549 {
10550   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10551
10552   return clutter_actor_get_paint_opacity_internal (self);
10553 }
10554
10555 /**
10556  * clutter_actor_get_opacity:
10557  * @self: a #ClutterActor
10558  *
10559  * Retrieves the opacity value of an actor, as set by
10560  * clutter_actor_set_opacity().
10561  *
10562  * For retrieving the absolute opacity of the actor inside a paint
10563  * virtual function, see clutter_actor_get_paint_opacity().
10564  *
10565  * Return value: the opacity of the actor
10566  */
10567 guint8
10568 clutter_actor_get_opacity (ClutterActor *self)
10569 {
10570   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10571
10572   return self->priv->opacity;
10573 }
10574
10575 /**
10576  * clutter_actor_set_offscreen_redirect:
10577  * @self: A #ClutterActor
10578  * @redirect: New offscreen redirect flags for the actor.
10579  *
10580  * Defines the circumstances where the actor should be redirected into
10581  * an offscreen image. The offscreen image is used to flatten the
10582  * actor into a single image while painting for two main reasons.
10583  * Firstly, when the actor is painted a second time without any of its
10584  * contents changing it can simply repaint the cached image without
10585  * descending further down the actor hierarchy. Secondly, it will make
10586  * the opacity look correct even if there are overlapping primitives
10587  * in the actor.
10588  *
10589  * Caching the actor could in some cases be a performance win and in
10590  * some cases be a performance lose so it is important to determine
10591  * which value is right for an actor before modifying this value. For
10592  * example, there is never any reason to flatten an actor that is just
10593  * a single texture (such as a #ClutterTexture) because it is
10594  * effectively already cached in an image so the offscreen would be
10595  * redundant. Also if the actor contains primitives that are far apart
10596  * with a large transparent area in the middle (such as a large
10597  * CluterGroup with a small actor in the top left and a small actor in
10598  * the bottom right) then the cached image will contain the entire
10599  * image of the large area and the paint will waste time blending all
10600  * of the transparent pixels in the middle.
10601  *
10602  * The default method of implementing opacity on a container simply
10603  * forwards on the opacity to all of the children. If the children are
10604  * overlapping then it will appear as if they are two separate glassy
10605  * objects and there will be a break in the color where they
10606  * overlap. By redirecting to an offscreen buffer it will be as if the
10607  * two opaque objects are combined into one and then made transparent
10608  * which is usually what is expected.
10609  *
10610  * The image below demonstrates the difference between redirecting and
10611  * not. The image shows two Clutter groups, each containing a red and
10612  * a green rectangle which overlap. The opacity on the group is set to
10613  * 128 (which is 50%). When the offscreen redirect is not used, the
10614  * red rectangle can be seen through the blue rectangle as if the two
10615  * rectangles were separately transparent. When the redirect is used
10616  * the group as a whole is transparent instead so the red rectangle is
10617  * not visible where they overlap.
10618  *
10619  * <figure id="offscreen-redirect">
10620  *   <title>Sample of using an offscreen redirect for transparency</title>
10621  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10622  * </figure>
10623  *
10624  * The default value for this property is 0, so we effectively will
10625  * never redirect an actor offscreen by default. This means that there
10626  * are times that transparent actors may look glassy as described
10627  * above. The reason this is the default is because there is a
10628  * performance trade off between quality and performance here. In many
10629  * cases the default form of glassy opacity looks good enough, but if
10630  * it's not you will need to set the
10631  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10632  * redirection for opacity.
10633  *
10634  * Custom actors that don't contain any overlapping primitives are
10635  * recommended to override the has_overlaps() virtual to return %FALSE
10636  * for maximum efficiency.
10637  *
10638  * Since: 1.8
10639  */
10640 void
10641 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10642                                       ClutterOffscreenRedirect redirect)
10643 {
10644   ClutterActorPrivate *priv;
10645
10646   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10647
10648   priv = self->priv;
10649
10650   if (priv->offscreen_redirect != redirect)
10651     {
10652       priv->offscreen_redirect = redirect;
10653
10654       /* Queue a redraw from the effect so that it can use its cached
10655          image if available instead of having to redraw the actual
10656          actor. If it doesn't end up using the FBO then the effect is
10657          still able to continue the paint anyway. If there is no
10658          effect then this is equivalent to queuing a full redraw */
10659       _clutter_actor_queue_redraw_full (self,
10660                                         0, /* flags */
10661                                         NULL, /* clip */
10662                                         priv->flatten_effect);
10663
10664       g_object_notify_by_pspec (G_OBJECT (self),
10665                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10666     }
10667 }
10668
10669 /**
10670  * clutter_actor_get_offscreen_redirect:
10671  * @self: a #ClutterActor
10672  *
10673  * Retrieves whether to redirect the actor to an offscreen buffer, as
10674  * set by clutter_actor_set_offscreen_redirect().
10675  *
10676  * Return value: the value of the offscreen-redirect property of the actor
10677  *
10678  * Since: 1.8
10679  */
10680 ClutterOffscreenRedirect
10681 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10682 {
10683   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10684
10685   return self->priv->offscreen_redirect;
10686 }
10687
10688 /**
10689  * clutter_actor_set_name:
10690  * @self: A #ClutterActor
10691  * @name: Textual tag to apply to actor
10692  *
10693  * Sets the given name to @self. The name can be used to identify
10694  * a #ClutterActor.
10695  */
10696 void
10697 clutter_actor_set_name (ClutterActor *self,
10698                         const gchar  *name)
10699 {
10700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10701
10702   g_free (self->priv->name);
10703   self->priv->name = g_strdup (name);
10704
10705   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10706 }
10707
10708 /**
10709  * clutter_actor_get_name:
10710  * @self: A #ClutterActor
10711  *
10712  * Retrieves the name of @self.
10713  *
10714  * Return value: the name of the actor, or %NULL. The returned string is
10715  *   owned by the actor and should not be modified or freed.
10716  */
10717 const gchar *
10718 clutter_actor_get_name (ClutterActor *self)
10719 {
10720   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10721
10722   return self->priv->name;
10723 }
10724
10725 /**
10726  * clutter_actor_get_gid:
10727  * @self: A #ClutterActor
10728  *
10729  * Retrieves the unique id for @self.
10730  *
10731  * Return value: Globally unique value for this object instance.
10732  *
10733  * Since: 0.6
10734  *
10735  * Deprecated: 1.8: The id is not used any longer.
10736  */
10737 guint32
10738 clutter_actor_get_gid (ClutterActor *self)
10739 {
10740   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10741
10742   return self->priv->id;
10743 }
10744
10745 static inline void
10746 clutter_actor_set_depth_internal (ClutterActor *self,
10747                                   float         depth)
10748 {
10749   ClutterTransformInfo *info;
10750
10751   info = _clutter_actor_get_transform_info (self);
10752
10753   if (info->depth != depth)
10754     {
10755       /* Sets Z value - XXX 2.0: should we invert? */
10756       info->depth = depth;
10757
10758       self->priv->transform_valid = FALSE;
10759
10760       /* FIXME - remove this crap; sadly, there are still containers
10761        * in Clutter that depend on this utter brain damage
10762        */
10763       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10764
10765       clutter_actor_queue_redraw (self);
10766
10767       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10768     }
10769 }
10770
10771 /**
10772  * clutter_actor_set_depth:
10773  * @self: a #ClutterActor
10774  * @depth: Z co-ord
10775  *
10776  * Sets the Z coordinate of @self to @depth.
10777  *
10778  * The unit used by @depth is dependant on the perspective setup. See
10779  * also clutter_stage_set_perspective().
10780  */
10781 void
10782 clutter_actor_set_depth (ClutterActor *self,
10783                          gfloat        depth)
10784 {
10785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10786
10787   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10788     {
10789       const ClutterTransformInfo *info;
10790
10791       info = _clutter_actor_get_transform_info_or_defaults (self);
10792
10793       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10794                                         info->depth,
10795                                         depth);
10796     }
10797   else
10798     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10799
10800   clutter_actor_queue_redraw (self);
10801 }
10802
10803 /**
10804  * clutter_actor_get_depth:
10805  * @self: a #ClutterActor
10806  *
10807  * Retrieves the depth of @self.
10808  *
10809  * Return value: the depth of the actor
10810  */
10811 gfloat
10812 clutter_actor_get_depth (ClutterActor *self)
10813 {
10814   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10815
10816   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10817 }
10818
10819 /**
10820  * clutter_actor_set_rotation:
10821  * @self: a #ClutterActor
10822  * @axis: the axis of rotation
10823  * @angle: the angle of rotation
10824  * @x: X coordinate of the rotation center
10825  * @y: Y coordinate of the rotation center
10826  * @z: Z coordinate of the rotation center
10827  *
10828  * Sets the rotation angle of @self around the given axis.
10829  *
10830  * The rotation center coordinates used depend on the value of @axis:
10831  * <itemizedlist>
10832  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10833  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10834  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10835  * </itemizedlist>
10836  *
10837  * The rotation coordinates are relative to the anchor point of the
10838  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10839  * point is set, the upper left corner is assumed as the origin.
10840  *
10841  * Since: 0.8
10842  */
10843 void
10844 clutter_actor_set_rotation (ClutterActor      *self,
10845                             ClutterRotateAxis  axis,
10846                             gdouble            angle,
10847                             gfloat             x,
10848                             gfloat             y,
10849                             gfloat             z)
10850 {
10851   ClutterVertex v;
10852
10853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10854
10855   v.x = x;
10856   v.y = y;
10857   v.z = z;
10858
10859   g_object_freeze_notify (G_OBJECT (self));
10860
10861   clutter_actor_set_rotation_angle (self, axis, angle);
10862   clutter_actor_set_rotation_center_internal (self, axis, &v);
10863
10864   g_object_thaw_notify (G_OBJECT (self));
10865 }
10866
10867 /**
10868  * clutter_actor_set_z_rotation_from_gravity:
10869  * @self: a #ClutterActor
10870  * @angle: the angle of rotation
10871  * @gravity: the center point of the rotation
10872  *
10873  * Sets the rotation angle of @self around the Z axis using the center
10874  * point specified as a compass point. For example to rotate such that
10875  * the center of the actor remains static you can use
10876  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10877  * will move accordingly.
10878  *
10879  * Since: 1.0
10880  */
10881 void
10882 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10883                                            gdouble         angle,
10884                                            ClutterGravity  gravity)
10885 {
10886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10887
10888   if (gravity == CLUTTER_GRAVITY_NONE)
10889     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10890   else
10891     {
10892       GObject *obj = G_OBJECT (self);
10893       ClutterTransformInfo *info;
10894
10895       info = _clutter_actor_get_transform_info (self);
10896
10897       g_object_freeze_notify (obj);
10898
10899       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10900
10901       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10902       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10903       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10904
10905       g_object_thaw_notify (obj);
10906     }
10907 }
10908
10909 /**
10910  * clutter_actor_get_rotation:
10911  * @self: a #ClutterActor
10912  * @axis: the axis of rotation
10913  * @x: (out): return value for the X coordinate of the center of rotation
10914  * @y: (out): return value for the Y coordinate of the center of rotation
10915  * @z: (out): return value for the Z coordinate of the center of rotation
10916  *
10917  * Retrieves the angle and center of rotation on the given axis,
10918  * set using clutter_actor_set_rotation().
10919  *
10920  * Return value: the angle of rotation
10921  *
10922  * Since: 0.8
10923  */
10924 gdouble
10925 clutter_actor_get_rotation (ClutterActor      *self,
10926                             ClutterRotateAxis  axis,
10927                             gfloat            *x,
10928                             gfloat            *y,
10929                             gfloat            *z)
10930 {
10931   const ClutterTransformInfo *info;
10932   const AnchorCoord *anchor_coord;
10933   gdouble retval = 0;
10934
10935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10936
10937   info = _clutter_actor_get_transform_info_or_defaults (self);
10938
10939   switch (axis)
10940     {
10941     case CLUTTER_X_AXIS:
10942       anchor_coord = &info->rx_center;
10943       retval = info->rx_angle;
10944       break;
10945
10946     case CLUTTER_Y_AXIS:
10947       anchor_coord = &info->ry_center;
10948       retval = info->ry_angle;
10949       break;
10950
10951     case CLUTTER_Z_AXIS:
10952       anchor_coord = &info->rz_center;
10953       retval = info->rz_angle;
10954       break;
10955
10956     default:
10957       anchor_coord = NULL;
10958       retval = 0.0;
10959       break;
10960     }
10961
10962   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10963
10964   return retval;
10965 }
10966
10967 /**
10968  * clutter_actor_get_z_rotation_gravity:
10969  * @self: A #ClutterActor
10970  *
10971  * Retrieves the center for the rotation around the Z axis as a
10972  * compass direction. If the center was specified in pixels or units
10973  * this will return %CLUTTER_GRAVITY_NONE.
10974  *
10975  * Return value: the Z rotation center
10976  *
10977  * Since: 1.0
10978  */
10979 ClutterGravity
10980 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10981 {
10982   const ClutterTransformInfo *info;
10983
10984   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10985
10986   info = _clutter_actor_get_transform_info_or_defaults (self);
10987
10988   return clutter_anchor_coord_get_gravity (&info->rz_center);
10989 }
10990
10991 /**
10992  * clutter_actor_set_clip:
10993  * @self: A #ClutterActor
10994  * @xoff: X offset of the clip rectangle
10995  * @yoff: Y offset of the clip rectangle
10996  * @width: Width of the clip rectangle
10997  * @height: Height of the clip rectangle
10998  *
10999  * Sets clip area for @self. The clip area is always computed from the
11000  * upper left corner of the actor, even if the anchor point is set
11001  * otherwise.
11002  *
11003  * Since: 0.6
11004  */
11005 void
11006 clutter_actor_set_clip (ClutterActor *self,
11007                         gfloat        xoff,
11008                         gfloat        yoff,
11009                         gfloat        width,
11010                         gfloat        height)
11011 {
11012   ClutterActorPrivate *priv;
11013
11014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11015
11016   priv = self->priv;
11017
11018   if (priv->has_clip &&
11019       priv->clip.x == xoff &&
11020       priv->clip.y == yoff &&
11021       priv->clip.width == width &&
11022       priv->clip.height == height)
11023     return;
11024
11025   priv->clip.x = xoff;
11026   priv->clip.y = yoff;
11027   priv->clip.width = width;
11028   priv->clip.height = height;
11029
11030   priv->has_clip = TRUE;
11031
11032   clutter_actor_queue_redraw (self);
11033
11034   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11035   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
11036 }
11037
11038 /**
11039  * clutter_actor_remove_clip:
11040  * @self: A #ClutterActor
11041  *
11042  * Removes clip area from @self.
11043  */
11044 void
11045 clutter_actor_remove_clip (ClutterActor *self)
11046 {
11047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11048
11049   if (!self->priv->has_clip)
11050     return;
11051
11052   self->priv->has_clip = FALSE;
11053
11054   clutter_actor_queue_redraw (self);
11055
11056   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11057 }
11058
11059 /**
11060  * clutter_actor_has_clip:
11061  * @self: a #ClutterActor
11062  *
11063  * Determines whether the actor has a clip area set or not.
11064  *
11065  * Return value: %TRUE if the actor has a clip area set.
11066  *
11067  * Since: 0.1.1
11068  */
11069 gboolean
11070 clutter_actor_has_clip (ClutterActor *self)
11071 {
11072   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11073
11074   return self->priv->has_clip;
11075 }
11076
11077 /**
11078  * clutter_actor_get_clip:
11079  * @self: a #ClutterActor
11080  * @xoff: (out) (allow-none): return location for the X offset of
11081  *   the clip rectangle, or %NULL
11082  * @yoff: (out) (allow-none): return location for the Y offset of
11083  *   the clip rectangle, or %NULL
11084  * @width: (out) (allow-none): return location for the width of
11085  *   the clip rectangle, or %NULL
11086  * @height: (out) (allow-none): return location for the height of
11087  *   the clip rectangle, or %NULL
11088  *
11089  * Gets the clip area for @self, if any is set
11090  *
11091  * Since: 0.6
11092  */
11093 void
11094 clutter_actor_get_clip (ClutterActor *self,
11095                         gfloat       *xoff,
11096                         gfloat       *yoff,
11097                         gfloat       *width,
11098                         gfloat       *height)
11099 {
11100   ClutterActorPrivate *priv;
11101
11102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11103
11104   priv = self->priv;
11105
11106   if (!priv->has_clip)
11107     return;
11108
11109   if (xoff != NULL)
11110     *xoff = priv->clip.x;
11111
11112   if (yoff != NULL)
11113     *yoff = priv->clip.y;
11114
11115   if (width != NULL)
11116     *width = priv->clip.width;
11117
11118   if (height != NULL)
11119     *height = priv->clip.height;
11120 }
11121
11122 /**
11123  * clutter_actor_get_children:
11124  * @self: a #ClutterActor
11125  *
11126  * Retrieves the list of children of @self.
11127  *
11128  * Return value: (transfer container) (element-type ClutterActor): A newly
11129  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11130  *   done.
11131  *
11132  * Since: 1.10
11133  */
11134 GList *
11135 clutter_actor_get_children (ClutterActor *self)
11136 {
11137   ClutterActor *iter;
11138   GList *res;
11139
11140   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11141
11142   /* we walk the list backward so that we can use prepend(),
11143    * which is O(1)
11144    */
11145   for (iter = self->priv->last_child, res = NULL;
11146        iter != NULL;
11147        iter = iter->priv->prev_sibling)
11148     {
11149       res = g_list_prepend (res, iter);
11150     }
11151
11152   return res;
11153 }
11154
11155 /*< private >
11156  * insert_child_at_depth:
11157  * @self: a #ClutterActor
11158  * @child: a #ClutterActor
11159  *
11160  * Inserts @child inside the list of children held by @self, using
11161  * the depth as the insertion criteria.
11162  *
11163  * This sadly makes the insertion not O(1), but we can keep the
11164  * list sorted so that the painters algorithm we use for painting
11165  * the children will work correctly.
11166  */
11167 static void
11168 insert_child_at_depth (ClutterActor *self,
11169                        ClutterActor *child,
11170                        gpointer      dummy G_GNUC_UNUSED)
11171 {
11172   ClutterActor *iter;
11173   float child_depth;
11174
11175   child->priv->parent = self;
11176
11177   child_depth =
11178     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11179
11180   /* special-case the first child */
11181   if (self->priv->n_children == 0)
11182     {
11183       self->priv->first_child = child;
11184       self->priv->last_child = child;
11185
11186       child->priv->next_sibling = NULL;
11187       child->priv->prev_sibling = NULL;
11188
11189       return;
11190     }
11191
11192   /* Find the right place to insert the child so that it will still be
11193      sorted and the child will be after all of the actors at the same
11194      dept */
11195   for (iter = self->priv->first_child;
11196        iter != NULL;
11197        iter = iter->priv->next_sibling)
11198     {
11199       float iter_depth;
11200
11201       iter_depth =
11202         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11203
11204       if (iter_depth > child_depth)
11205         break;
11206     }
11207
11208   if (iter != NULL)
11209     {
11210       ClutterActor *tmp = iter->priv->prev_sibling;
11211
11212       if (tmp != NULL)
11213         tmp->priv->next_sibling = child;
11214
11215       /* Insert the node before the found one */
11216       child->priv->prev_sibling = iter->priv->prev_sibling;
11217       child->priv->next_sibling = iter;
11218       iter->priv->prev_sibling = child;
11219     }
11220   else
11221     {
11222       ClutterActor *tmp = self->priv->last_child;
11223
11224       if (tmp != NULL)
11225         tmp->priv->next_sibling = child;
11226
11227       /* insert the node at the end of the list */
11228       child->priv->prev_sibling = self->priv->last_child;
11229       child->priv->next_sibling = NULL;
11230     }
11231
11232   if (child->priv->prev_sibling == NULL)
11233     self->priv->first_child = child;
11234
11235   if (child->priv->next_sibling == NULL)
11236     self->priv->last_child = child;
11237 }
11238
11239 static void
11240 insert_child_at_index (ClutterActor *self,
11241                        ClutterActor *child,
11242                        gpointer      data_)
11243 {
11244   gint index_ = GPOINTER_TO_INT (data_);
11245
11246   child->priv->parent = self;
11247
11248   if (index_ == 0)
11249     {
11250       ClutterActor *tmp = self->priv->first_child;
11251
11252       if (tmp != NULL)
11253         tmp->priv->prev_sibling = child;
11254
11255       child->priv->prev_sibling = NULL;
11256       child->priv->next_sibling = tmp;
11257     }
11258   else if (index_ < 0 || index_ >= self->priv->n_children)
11259     {
11260       ClutterActor *tmp = self->priv->last_child;
11261
11262       if (tmp != NULL)
11263         tmp->priv->next_sibling = child;
11264
11265       child->priv->prev_sibling = tmp;
11266       child->priv->next_sibling = NULL;
11267     }
11268   else
11269     {
11270       ClutterActor *iter;
11271       int i;
11272
11273       for (iter = self->priv->first_child, i = 0;
11274            iter != NULL;
11275            iter = iter->priv->next_sibling, i += 1)
11276         {
11277           if (index_ == i)
11278             {
11279               ClutterActor *tmp = iter->priv->prev_sibling;
11280
11281               child->priv->prev_sibling = tmp;
11282               child->priv->next_sibling = iter;
11283
11284               iter->priv->prev_sibling = child;
11285
11286               if (tmp != NULL)
11287                 tmp->priv->next_sibling = child;
11288
11289               break;
11290             }
11291         }
11292     }
11293
11294   if (child->priv->prev_sibling == NULL)
11295     self->priv->first_child = child;
11296
11297   if (child->priv->next_sibling == NULL)
11298     self->priv->last_child = child;
11299 }
11300
11301 static void
11302 insert_child_above (ClutterActor *self,
11303                     ClutterActor *child,
11304                     gpointer      data)
11305 {
11306   ClutterActor *sibling = data;
11307
11308   child->priv->parent = self;
11309
11310   if (sibling == NULL)
11311     sibling = self->priv->last_child;
11312
11313   child->priv->prev_sibling = sibling;
11314
11315   if (sibling != NULL)
11316     {
11317       ClutterActor *tmp = sibling->priv->next_sibling;
11318
11319       child->priv->next_sibling = tmp;
11320
11321       if (tmp != NULL)
11322         tmp->priv->prev_sibling = child;
11323
11324       sibling->priv->next_sibling = child;
11325     }
11326   else
11327     child->priv->next_sibling = NULL;
11328
11329   if (child->priv->prev_sibling == NULL)
11330     self->priv->first_child = child;
11331
11332   if (child->priv->next_sibling == NULL)
11333     self->priv->last_child = child;
11334 }
11335
11336 static void
11337 insert_child_below (ClutterActor *self,
11338                     ClutterActor *child,
11339                     gpointer      data)
11340 {
11341   ClutterActor *sibling = data;
11342
11343   child->priv->parent = self;
11344
11345   if (sibling == NULL)
11346     sibling = self->priv->first_child;
11347
11348   child->priv->next_sibling = sibling;
11349
11350   if (sibling != NULL)
11351     {
11352       ClutterActor *tmp = sibling->priv->prev_sibling;
11353
11354       child->priv->prev_sibling = tmp;
11355
11356       if (tmp != NULL)
11357         tmp->priv->next_sibling = child;
11358
11359       sibling->priv->prev_sibling = child;
11360     }
11361   else
11362     child->priv->prev_sibling = NULL;
11363
11364   if (child->priv->prev_sibling == NULL)
11365     self->priv->first_child = child;
11366
11367   if (child->priv->next_sibling == NULL)
11368     self->priv->last_child = child;
11369 }
11370
11371 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11372                                            ClutterActor *child,
11373                                            gpointer      data);
11374
11375 typedef enum {
11376   ADD_CHILD_CREATE_META        = 1 << 0,
11377   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11378   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11379   ADD_CHILD_CHECK_STATE        = 1 << 3,
11380   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11381   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11382
11383   /* default flags for public API */
11384   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11385                                ADD_CHILD_EMIT_PARENT_SET |
11386                                ADD_CHILD_EMIT_ACTOR_ADDED |
11387                                ADD_CHILD_CHECK_STATE |
11388                                ADD_CHILD_NOTIFY_FIRST_LAST |
11389                                ADD_CHILD_SHOW_ON_SET_PARENT,
11390
11391   /* flags for legacy/deprecated API */
11392   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11393                                ADD_CHILD_CHECK_STATE |
11394                                ADD_CHILD_NOTIFY_FIRST_LAST |
11395                                ADD_CHILD_SHOW_ON_SET_PARENT
11396 } ClutterActorAddChildFlags;
11397
11398 /*< private >
11399  * clutter_actor_add_child_internal:
11400  * @self: a #ClutterActor
11401  * @child: a #ClutterActor
11402  * @flags: control flags for actions
11403  * @add_func: delegate function
11404  * @data: (closure): data to pass to @add_func
11405  *
11406  * Adds @child to the list of children of @self.
11407  *
11408  * The actual insertion inside the list is delegated to @add_func: this
11409  * function will just set up the state, perform basic checks, and emit
11410  * signals.
11411  *
11412  * The @flags argument is used to perform additional operations.
11413  */
11414 static inline void
11415 clutter_actor_add_child_internal (ClutterActor              *self,
11416                                   ClutterActor              *child,
11417                                   ClutterActorAddChildFlags  flags,
11418                                   ClutterActorAddChildFunc   add_func,
11419                                   gpointer                   data)
11420 {
11421   ClutterTextDirection text_dir;
11422   gboolean create_meta;
11423   gboolean emit_parent_set, emit_actor_added;
11424   gboolean check_state;
11425   gboolean notify_first_last;
11426   gboolean show_on_set_parent;
11427   ClutterActor *old_first_child, *old_last_child;
11428
11429   if (child->priv->parent != NULL)
11430     {
11431       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11432                  "use clutter_actor_remove_child() first.",
11433                  _clutter_actor_get_debug_name (child),
11434                  _clutter_actor_get_debug_name (child->priv->parent));
11435       return;
11436     }
11437
11438   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11439     {
11440       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11441                  "a child of another actor.",
11442                  _clutter_actor_get_debug_name (child));
11443       return;
11444     }
11445
11446 #if 0
11447   /* XXX - this check disallows calling methods that change the stacking
11448    * order within the destruction sequence, by triggering a critical
11449    * warning first, and leaving the actor in an undefined state, which
11450    * then ends up being caught by an assertion.
11451    *
11452    * the reproducible sequence is:
11453    *
11454    *   - actor gets destroyed;
11455    *   - another actor, linked to the first, will try to change the
11456    *     stacking order of the first actor;
11457    *   - changing the stacking order is a composite operation composed
11458    *     by the following steps:
11459    *     1. ref() the child;
11460    *     2. remove_child_internal(), which removes the reference;
11461    *     3. add_child_internal(), which adds a reference;
11462    *   - the state of the actor is not changed between (2) and (3), as
11463    *     it could be an expensive recomputation;
11464    *   - if (3) bails out, then the actor is in an undefined state, but
11465    *     still alive;
11466    *   - the destruction sequence terminates, but the actor is unparented
11467    *     while its state indicates being parented instead.
11468    *   - assertion failure.
11469    *
11470    * the obvious fix would be to decompose each set_child_*_sibling()
11471    * method into proper remove_child()/add_child(), with state validation;
11472    * this may cause excessive work, though, and trigger a cascade of other
11473    * bugs in code that assumes that a change in the stacking order is an
11474    * atomic operation.
11475    *
11476    * another potential fix is to just remove this check here, and let
11477    * code doing stacking order changes inside the destruction sequence
11478    * of an actor continue doing the work.
11479    *
11480    * the third fix is to silently bail out early from every
11481    * set_child_*_sibling() and set_child_at_index() method, and avoid
11482    * doing work.
11483    *
11484    * I have a preference for the second solution, since it involves the
11485    * least amount of work, and the least amount of code duplication.
11486    *
11487    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11488    */
11489   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11490     {
11491       g_warning ("The actor '%s' is currently being destroyed, and "
11492                  "cannot be added as a child of another actor.",
11493                  _clutter_actor_get_debug_name (child));
11494       return;
11495     }
11496 #endif
11497
11498   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11499   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11500   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11501   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11502   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11503   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11504
11505   old_first_child = self->priv->first_child;
11506   old_last_child = self->priv->last_child;
11507
11508   g_object_freeze_notify (G_OBJECT (self));
11509
11510   if (create_meta)
11511     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11512
11513   g_object_ref_sink (child);
11514   child->priv->parent = NULL;
11515   child->priv->next_sibling = NULL;
11516   child->priv->prev_sibling = NULL;
11517
11518   /* delegate the actual insertion */
11519   add_func (self, child, data);
11520
11521   g_assert (child->priv->parent == self);
11522
11523   self->priv->n_children += 1;
11524
11525   self->priv->age += 1;
11526
11527   /* if push_internal() has been called then we automatically set
11528    * the flag on the actor
11529    */
11530   if (self->priv->internal_child)
11531     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11532
11533   /* children may cause their parent to expand, if they are set
11534    * to expand; if a child is not expanded then it cannot change
11535    * its parent's state. any further change later on will queue
11536    * an expand state check.
11537    *
11538    * this check, with the initial state of the needs_compute_expand
11539    * flag set to FALSE, should avoid recomputing the expand flags
11540    * state while building the actor tree.
11541    */
11542   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11543       (child->priv->needs_compute_expand ||
11544        child->priv->needs_x_expand ||
11545        child->priv->needs_y_expand))
11546     {
11547       clutter_actor_queue_compute_expand (self);
11548     }
11549
11550   /* clutter_actor_reparent() will emit ::parent-set for us */
11551   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11552     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11553
11554   if (check_state)
11555     {
11556       /* If parent is mapped or realized, we need to also be mapped or
11557        * realized once we're inside the parent.
11558        */
11559       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11560
11561       /* propagate the parent's text direction to the child */
11562       text_dir = clutter_actor_get_text_direction (self);
11563       clutter_actor_set_text_direction (child, text_dir);
11564     }
11565
11566   if (show_on_set_parent && child->priv->show_on_set_parent)
11567     clutter_actor_show (child);
11568
11569   if (CLUTTER_ACTOR_IS_MAPPED (child))
11570     clutter_actor_queue_redraw (child);
11571
11572   /* maintain the invariant that if an actor needs layout,
11573    * its parents do as well
11574    */
11575   if (child->priv->needs_width_request ||
11576       child->priv->needs_height_request ||
11577       child->priv->needs_allocation)
11578     {
11579       /* we work around the short-circuiting we do
11580        * in clutter_actor_queue_relayout() since we
11581        * want to force a relayout
11582        */
11583       child->priv->needs_width_request = TRUE;
11584       child->priv->needs_height_request = TRUE;
11585       child->priv->needs_allocation = TRUE;
11586
11587       clutter_actor_queue_relayout (child->priv->parent);
11588     }
11589
11590   if (emit_actor_added)
11591     g_signal_emit_by_name (self, "actor-added", child);
11592
11593   if (notify_first_last)
11594     {
11595       if (old_first_child != self->priv->first_child)
11596         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11597
11598       if (old_last_child != self->priv->last_child)
11599         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11600     }
11601
11602   g_object_thaw_notify (G_OBJECT (self));
11603 }
11604
11605 /**
11606  * clutter_actor_add_child:
11607  * @self: a #ClutterActor
11608  * @child: a #ClutterActor
11609  *
11610  * Adds @child to the children of @self.
11611  *
11612  * This function will acquire a reference on @child that will only
11613  * be released when calling clutter_actor_remove_child().
11614  *
11615  * This function will take into consideration the #ClutterActor:depth
11616  * of @child, and will keep the list of children sorted.
11617  *
11618  * This function will emit the #ClutterContainer::actor-added signal
11619  * on @self.
11620  *
11621  * Since: 1.10
11622  */
11623 void
11624 clutter_actor_add_child (ClutterActor *self,
11625                          ClutterActor *child)
11626 {
11627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11628   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11629   g_return_if_fail (self != child);
11630   g_return_if_fail (child->priv->parent == NULL);
11631
11632   clutter_actor_add_child_internal (self, child,
11633                                     ADD_CHILD_DEFAULT_FLAGS,
11634                                     insert_child_at_depth,
11635                                     NULL);
11636 }
11637
11638 /**
11639  * clutter_actor_insert_child_at_index:
11640  * @self: a #ClutterActor
11641  * @child: a #ClutterActor
11642  * @index_: the index
11643  *
11644  * Inserts @child into the list of children of @self, using the
11645  * given @index_. If @index_ is greater than the number of children
11646  * in @self, or is less than 0, then the new child is added at the end.
11647  *
11648  * This function will acquire a reference on @child that will only
11649  * be released when calling clutter_actor_remove_child().
11650  *
11651  * This function will not take into consideration the #ClutterActor:depth
11652  * of @child.
11653  *
11654  * This function will emit the #ClutterContainer::actor-added signal
11655  * on @self.
11656  *
11657  * Since: 1.10
11658  */
11659 void
11660 clutter_actor_insert_child_at_index (ClutterActor *self,
11661                                      ClutterActor *child,
11662                                      gint          index_)
11663 {
11664   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11665   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11666   g_return_if_fail (self != child);
11667   g_return_if_fail (child->priv->parent == NULL);
11668
11669   clutter_actor_add_child_internal (self, child,
11670                                     ADD_CHILD_DEFAULT_FLAGS,
11671                                     insert_child_at_index,
11672                                     GINT_TO_POINTER (index_));
11673 }
11674
11675 /**
11676  * clutter_actor_insert_child_above:
11677  * @self: a #ClutterActor
11678  * @child: a #ClutterActor
11679  * @sibling: (allow-none): a child of @self, or %NULL
11680  *
11681  * Inserts @child into the list of children of @self, above another
11682  * child of @self or, if @sibling is %NULL, above all the children
11683  * of @self.
11684  *
11685  * This function will acquire a reference on @child that will only
11686  * be released when calling clutter_actor_remove_child().
11687  *
11688  * This function will not take into consideration the #ClutterActor:depth
11689  * of @child.
11690  *
11691  * This function will emit the #ClutterContainer::actor-added signal
11692  * on @self.
11693  *
11694  * Since: 1.10
11695  */
11696 void
11697 clutter_actor_insert_child_above (ClutterActor *self,
11698                                   ClutterActor *child,
11699                                   ClutterActor *sibling)
11700 {
11701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11702   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11703   g_return_if_fail (self != child);
11704   g_return_if_fail (child != sibling);
11705   g_return_if_fail (child->priv->parent == NULL);
11706   g_return_if_fail (sibling == NULL ||
11707                     (CLUTTER_IS_ACTOR (sibling) &&
11708                      sibling->priv->parent == self));
11709
11710   clutter_actor_add_child_internal (self, child,
11711                                     ADD_CHILD_DEFAULT_FLAGS,
11712                                     insert_child_above,
11713                                     sibling);
11714 }
11715
11716 /**
11717  * clutter_actor_insert_child_below:
11718  * @self: a #ClutterActor
11719  * @child: a #ClutterActor
11720  * @sibling: (allow-none): a child of @self, or %NULL
11721  *
11722  * Inserts @child into the list of children of @self, below another
11723  * child of @self or, if @sibling is %NULL, below all the children
11724  * of @self.
11725  *
11726  * This function will acquire a reference on @child that will only
11727  * be released when calling clutter_actor_remove_child().
11728  *
11729  * This function will not take into consideration the #ClutterActor:depth
11730  * of @child.
11731  *
11732  * This function will emit the #ClutterContainer::actor-added signal
11733  * on @self.
11734  *
11735  * Since: 1.10
11736  */
11737 void
11738 clutter_actor_insert_child_below (ClutterActor *self,
11739                                   ClutterActor *child,
11740                                   ClutterActor *sibling)
11741 {
11742   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11743   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11744   g_return_if_fail (self != child);
11745   g_return_if_fail (child != sibling);
11746   g_return_if_fail (child->priv->parent == NULL);
11747   g_return_if_fail (sibling == NULL ||
11748                     (CLUTTER_IS_ACTOR (sibling) &&
11749                      sibling->priv->parent == self));
11750
11751   clutter_actor_add_child_internal (self, child,
11752                                     ADD_CHILD_DEFAULT_FLAGS,
11753                                     insert_child_below,
11754                                     sibling);
11755 }
11756
11757 /**
11758  * clutter_actor_set_parent:
11759  * @self: A #ClutterActor
11760  * @parent: A new #ClutterActor parent
11761  *
11762  * Sets the parent of @self to @parent.
11763  *
11764  * This function will result in @parent acquiring a reference on @self,
11765  * eventually by sinking its floating reference first. The reference
11766  * will be released by clutter_actor_unparent().
11767  *
11768  * This function should only be called by legacy #ClutterActor<!-- -->s
11769  * implementing the #ClutterContainer interface.
11770  *
11771  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11772  */
11773 void
11774 clutter_actor_set_parent (ClutterActor *self,
11775                           ClutterActor *parent)
11776 {
11777   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11778   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11779   g_return_if_fail (self != parent);
11780   g_return_if_fail (self->priv->parent == NULL);
11781
11782   /* as this function will be called inside ClutterContainer::add
11783    * implementations or when building up a composite actor, we have
11784    * to preserve the old behaviour, and not create child meta or
11785    * emit the ::actor-added signal, to avoid recursion or double
11786    * emissions
11787    */
11788   clutter_actor_add_child_internal (parent, self,
11789                                     ADD_CHILD_LEGACY_FLAGS,
11790                                     insert_child_at_depth,
11791                                     NULL);
11792 }
11793
11794 /**
11795  * clutter_actor_get_parent:
11796  * @self: A #ClutterActor
11797  *
11798  * Retrieves the parent of @self.
11799  *
11800  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11801  *  if no parent is set
11802  */
11803 ClutterActor *
11804 clutter_actor_get_parent (ClutterActor *self)
11805 {
11806   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11807
11808   return self->priv->parent;
11809 }
11810
11811 /**
11812  * clutter_actor_get_paint_visibility:
11813  * @self: A #ClutterActor
11814  *
11815  * Retrieves the 'paint' visibility of an actor recursively checking for non
11816  * visible parents.
11817  *
11818  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11819  *
11820  * Return Value: %TRUE if the actor is visibile and will be painted.
11821  *
11822  * Since: 0.8.4
11823  */
11824 gboolean
11825 clutter_actor_get_paint_visibility (ClutterActor *actor)
11826 {
11827   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11828
11829   return CLUTTER_ACTOR_IS_MAPPED (actor);
11830 }
11831
11832 /**
11833  * clutter_actor_remove_child:
11834  * @self: a #ClutterActor
11835  * @child: a #ClutterActor
11836  *
11837  * Removes @child from the children of @self.
11838  *
11839  * This function will release the reference added by
11840  * clutter_actor_add_child(), so if you want to keep using @child
11841  * you will have to acquire a referenced on it before calling this
11842  * function.
11843  *
11844  * This function will emit the #ClutterContainer::actor-removed
11845  * signal on @self.
11846  *
11847  * Since: 1.10
11848  */
11849 void
11850 clutter_actor_remove_child (ClutterActor *self,
11851                             ClutterActor *child)
11852 {
11853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11854   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11855   g_return_if_fail (self != child);
11856   g_return_if_fail (child->priv->parent != NULL);
11857   g_return_if_fail (child->priv->parent == self);
11858
11859   clutter_actor_remove_child_internal (self, child,
11860                                        REMOVE_CHILD_DEFAULT_FLAGS);
11861 }
11862
11863 /**
11864  * clutter_actor_remove_all_children:
11865  * @self: a #ClutterActor
11866  *
11867  * Removes all children of @self.
11868  *
11869  * This function releases the reference added by inserting a child actor
11870  * in the list of children of @self.
11871  *
11872  * If the reference count of a child drops to zero, the child will be
11873  * destroyed. If you want to ensure the destruction of all the children
11874  * of @self, use clutter_actor_destroy_all_children().
11875  *
11876  * Since: 1.10
11877  */
11878 void
11879 clutter_actor_remove_all_children (ClutterActor *self)
11880 {
11881   ClutterActorIter iter;
11882
11883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11884
11885   if (self->priv->n_children == 0)
11886     return;
11887
11888   g_object_freeze_notify (G_OBJECT (self));
11889
11890   clutter_actor_iter_init (&iter, self);
11891   while (clutter_actor_iter_next (&iter, NULL))
11892     clutter_actor_iter_remove (&iter);
11893
11894   g_object_thaw_notify (G_OBJECT (self));
11895
11896   /* sanity check */
11897   g_assert (self->priv->first_child == NULL);
11898   g_assert (self->priv->last_child == NULL);
11899   g_assert (self->priv->n_children == 0);
11900 }
11901
11902 /**
11903  * clutter_actor_destroy_all_children:
11904  * @self: a #ClutterActor
11905  *
11906  * Destroys all children of @self.
11907  *
11908  * This function releases the reference added by inserting a child
11909  * actor in the list of children of @self, and ensures that the
11910  * #ClutterActor::destroy signal is emitted on each child of the
11911  * actor.
11912  *
11913  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11914  * when its reference count drops to 0; the default handler of the
11915  * #ClutterActor::destroy signal will destroy all the children of an
11916  * actor. This function ensures that all children are destroyed, instead
11917  * of just removed from @self, unlike clutter_actor_remove_all_children()
11918  * which will merely release the reference and remove each child.
11919  *
11920  * Unless you acquired an additional reference on each child of @self
11921  * prior to calling clutter_actor_remove_all_children() and want to reuse
11922  * the actors, you should use clutter_actor_destroy_all_children() in
11923  * order to make sure that children are destroyed and signal handlers
11924  * are disconnected even in cases where circular references prevent this
11925  * from automatically happening through reference counting alone.
11926  *
11927  * Since: 1.10
11928  */
11929 void
11930 clutter_actor_destroy_all_children (ClutterActor *self)
11931 {
11932   ClutterActorIter iter;
11933
11934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11935
11936   if (self->priv->n_children == 0)
11937     return;
11938
11939   g_object_freeze_notify (G_OBJECT (self));
11940
11941   clutter_actor_iter_init (&iter, self);
11942   while (clutter_actor_iter_next (&iter, NULL))
11943     clutter_actor_iter_destroy (&iter);
11944
11945   g_object_thaw_notify (G_OBJECT (self));
11946
11947   /* sanity check */
11948   g_assert (self->priv->first_child == NULL);
11949   g_assert (self->priv->last_child == NULL);
11950   g_assert (self->priv->n_children == 0);
11951 }
11952
11953 typedef struct _InsertBetweenData {
11954   ClutterActor *prev_sibling;
11955   ClutterActor *next_sibling;
11956 } InsertBetweenData;
11957
11958 static void
11959 insert_child_between (ClutterActor *self,
11960                       ClutterActor *child,
11961                       gpointer      data_)
11962 {
11963   InsertBetweenData *data = data_;
11964   ClutterActor *prev_sibling = data->prev_sibling;
11965   ClutterActor *next_sibling = data->next_sibling;
11966
11967   child->priv->parent = self;
11968   child->priv->prev_sibling = prev_sibling;
11969   child->priv->next_sibling = next_sibling;
11970
11971   if (prev_sibling != NULL)
11972     prev_sibling->priv->next_sibling = child;
11973
11974   if (next_sibling != NULL)
11975     next_sibling->priv->prev_sibling = child;
11976
11977   if (child->priv->prev_sibling == NULL)
11978     self->priv->first_child = child;
11979
11980   if (child->priv->next_sibling == NULL)
11981     self->priv->last_child = child;
11982 }
11983
11984 /**
11985  * clutter_actor_replace_child:
11986  * @self: a #ClutterActor
11987  * @old_child: the child of @self to replace
11988  * @new_child: the #ClutterActor to replace @old_child
11989  *
11990  * Replaces @old_child with @new_child in the list of children of @self.
11991  *
11992  * Since: 1.10
11993  */
11994 void
11995 clutter_actor_replace_child (ClutterActor *self,
11996                              ClutterActor *old_child,
11997                              ClutterActor *new_child)
11998 {
11999   ClutterActor *prev_sibling, *next_sibling;
12000   InsertBetweenData clos;
12001
12002   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12003   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
12004   g_return_if_fail (old_child->priv->parent == self);
12005   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
12006   g_return_if_fail (old_child != new_child);
12007   g_return_if_fail (new_child != self);
12008   g_return_if_fail (new_child->priv->parent == NULL);
12009
12010   prev_sibling = old_child->priv->prev_sibling;
12011   next_sibling = old_child->priv->next_sibling;
12012   clutter_actor_remove_child_internal (self, old_child,
12013                                        REMOVE_CHILD_DEFAULT_FLAGS);
12014
12015   clos.prev_sibling = prev_sibling;
12016   clos.next_sibling = next_sibling;
12017   clutter_actor_add_child_internal (self, new_child,
12018                                     ADD_CHILD_DEFAULT_FLAGS,
12019                                     insert_child_between,
12020                                     &clos);
12021 }
12022
12023 /**
12024  * clutter_actor_unparent:
12025  * @self: a #ClutterActor
12026  *
12027  * Removes the parent of @self.
12028  *
12029  * This will cause the parent of @self to release the reference
12030  * acquired when calling clutter_actor_set_parent(), so if you
12031  * want to keep @self you will have to acquire a reference of
12032  * your own, through g_object_ref().
12033  *
12034  * This function should only be called by legacy #ClutterActor<!-- -->s
12035  * implementing the #ClutterContainer interface.
12036  *
12037  * Since: 0.1.1
12038  *
12039  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12040  */
12041 void
12042 clutter_actor_unparent (ClutterActor *self)
12043 {
12044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12045
12046   if (self->priv->parent == NULL)
12047     return;
12048
12049   clutter_actor_remove_child_internal (self->priv->parent, self,
12050                                        REMOVE_CHILD_LEGACY_FLAGS);
12051 }
12052
12053 /**
12054  * clutter_actor_reparent:
12055  * @self: a #ClutterActor
12056  * @new_parent: the new #ClutterActor parent
12057  *
12058  * Resets the parent actor of @self.
12059  *
12060  * This function is logically equivalent to calling clutter_actor_unparent()
12061  * and clutter_actor_set_parent(), but more efficiently implemented, as it
12062  * ensures the child is not finalized when unparented, and emits the
12063  * #ClutterActor::parent-set signal only once.
12064  *
12065  * In reality, calling this function is less useful than it sounds, as some
12066  * application code may rely on changes in the intermediate state between
12067  * removal and addition of the actor from its old parent to the @new_parent.
12068  * Thus, it is strongly encouraged to avoid using this function in application
12069  * code.
12070  *
12071  * Since: 0.2
12072  *
12073  * Deprecated: 1.10: Use clutter_actor_remove_child() and
12074  *   clutter_actor_add_child() instead; remember to take a reference on
12075  *   the actor being removed before calling clutter_actor_remove_child()
12076  *   to avoid the reference count dropping to zero and the actor being
12077  *   destroyed.
12078  */
12079 void
12080 clutter_actor_reparent (ClutterActor *self,
12081                         ClutterActor *new_parent)
12082 {
12083   ClutterActorPrivate *priv;
12084
12085   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12086   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12087   g_return_if_fail (self != new_parent);
12088
12089   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12090     {
12091       g_warning ("Cannot set a parent on a toplevel actor");
12092       return;
12093     }
12094
12095   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12096     {
12097       g_warning ("Cannot set a parent currently being destroyed");
12098       return;
12099     }
12100
12101   priv = self->priv;
12102
12103   if (priv->parent != new_parent)
12104     {
12105       ClutterActor *old_parent;
12106
12107       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12108
12109       old_parent = priv->parent;
12110
12111       g_object_ref (self);
12112
12113       if (old_parent != NULL)
12114         {
12115          /* go through the Container implementation if this is a regular
12116           * child and not an internal one
12117           */
12118          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12119            {
12120              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12121
12122              /* this will have to call unparent() */
12123              clutter_container_remove_actor (parent, self);
12124            }
12125          else
12126            clutter_actor_remove_child_internal (old_parent, self,
12127                                                 REMOVE_CHILD_LEGACY_FLAGS);
12128         }
12129
12130       /* Note, will call set_parent() */
12131       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12132         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12133       else
12134         clutter_actor_add_child_internal (new_parent, self,
12135                                           ADD_CHILD_LEGACY_FLAGS,
12136                                           insert_child_at_depth,
12137                                           NULL);
12138
12139       /* we emit the ::parent-set signal once */
12140       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12141
12142       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12143
12144       /* the IN_REPARENT flag suspends state updates */
12145       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12146
12147       g_object_unref (self);
12148    }
12149 }
12150
12151 /**
12152  * clutter_actor_contains:
12153  * @self: A #ClutterActor
12154  * @descendant: A #ClutterActor, possibly contained in @self
12155  *
12156  * Determines if @descendant is contained inside @self (either as an
12157  * immediate child, or as a deeper descendant). If @self and
12158  * @descendant point to the same actor then it will also return %TRUE.
12159  *
12160  * Return value: whether @descendent is contained within @self
12161  *
12162  * Since: 1.4
12163  */
12164 gboolean
12165 clutter_actor_contains (ClutterActor *self,
12166                         ClutterActor *descendant)
12167 {
12168   ClutterActor *actor;
12169
12170   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12171   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12172
12173   for (actor = descendant; actor; actor = actor->priv->parent)
12174     if (actor == self)
12175       return TRUE;
12176
12177   return FALSE;
12178 }
12179
12180 /**
12181  * clutter_actor_set_child_above_sibling:
12182  * @self: a #ClutterActor
12183  * @child: a #ClutterActor child of @self
12184  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12185  *
12186  * Sets @child to be above @sibling in the list of children of @self.
12187  *
12188  * If @sibling is %NULL, @child will be the new last child of @self.
12189  *
12190  * This function is logically equivalent to removing @child and using
12191  * clutter_actor_insert_child_above(), but it will not emit signals
12192  * or change state on @child.
12193  *
12194  * Since: 1.10
12195  */
12196 void
12197 clutter_actor_set_child_above_sibling (ClutterActor *self,
12198                                        ClutterActor *child,
12199                                        ClutterActor *sibling)
12200 {
12201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12202   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12203   g_return_if_fail (child->priv->parent == self);
12204   g_return_if_fail (child != sibling);
12205   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12206
12207   if (sibling != NULL)
12208     g_return_if_fail (sibling->priv->parent == self);
12209
12210   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12211       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12212       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12213     return;
12214
12215   /* we don't want to change the state of child, or emit signals, or
12216    * regenerate ChildMeta instances here, but we still want to follow
12217    * the correct sequence of steps encoded in remove_child() and
12218    * add_child(), so that correctness is ensured, and we only go
12219    * through one known code path.
12220    */
12221   g_object_ref (child);
12222   clutter_actor_remove_child_internal (self, child, 0);
12223   clutter_actor_add_child_internal (self, child,
12224                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12225                                     insert_child_above,
12226                                     sibling);
12227
12228   clutter_actor_queue_relayout (self);
12229 }
12230
12231 /**
12232  * clutter_actor_set_child_below_sibling:
12233  * @self: a #ClutterActor
12234  * @child: a #ClutterActor child of @self
12235  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12236  *
12237  * Sets @child to be below @sibling in the list of children of @self.
12238  *
12239  * If @sibling is %NULL, @child will be the new first child of @self.
12240  *
12241  * This function is logically equivalent to removing @self and using
12242  * clutter_actor_insert_child_below(), but it will not emit signals
12243  * or change state on @child.
12244  *
12245  * Since: 1.10
12246  */
12247 void
12248 clutter_actor_set_child_below_sibling (ClutterActor *self,
12249                                        ClutterActor *child,
12250                                        ClutterActor *sibling)
12251 {
12252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12253   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12254   g_return_if_fail (child->priv->parent == self);
12255   g_return_if_fail (child != sibling);
12256   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12257
12258   if (sibling != NULL)
12259     g_return_if_fail (sibling->priv->parent == self);
12260
12261   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12262       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12263       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12264     return;
12265
12266   /* see the comment in set_child_above_sibling() */
12267   g_object_ref (child);
12268   clutter_actor_remove_child_internal (self, child, 0);
12269   clutter_actor_add_child_internal (self, child,
12270                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12271                                     insert_child_below,
12272                                     sibling);
12273
12274   clutter_actor_queue_relayout (self);
12275 }
12276
12277 /**
12278  * clutter_actor_set_child_at_index:
12279  * @self: a #ClutterActor
12280  * @child: a #ClutterActor child of @self
12281  * @index_: the new index for @child
12282  *
12283  * Changes the index of @child in the list of children of @self.
12284  *
12285  * This function is logically equivalent to removing @child and
12286  * calling clutter_actor_insert_child_at_index(), but it will not
12287  * emit signals or change state on @child.
12288  *
12289  * Since: 1.10
12290  */
12291 void
12292 clutter_actor_set_child_at_index (ClutterActor *self,
12293                                   ClutterActor *child,
12294                                   gint          index_)
12295 {
12296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12297   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12298   g_return_if_fail (child->priv->parent == self);
12299   g_return_if_fail (index_ <= self->priv->n_children);
12300
12301   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12302       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12303     return;
12304
12305   g_object_ref (child);
12306   clutter_actor_remove_child_internal (self, child, 0);
12307   clutter_actor_add_child_internal (self, child,
12308                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12309                                     insert_child_at_index,
12310                                     GINT_TO_POINTER (index_));
12311
12312   clutter_actor_queue_relayout (self);
12313 }
12314
12315 /**
12316  * clutter_actor_raise:
12317  * @self: A #ClutterActor
12318  * @below: (allow-none): A #ClutterActor to raise above.
12319  *
12320  * Puts @self above @below.
12321  *
12322  * Both actors must have the same parent, and the parent must implement
12323  * the #ClutterContainer interface
12324  *
12325  * This function calls clutter_container_raise_child() internally.
12326  *
12327  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12328  */
12329 void
12330 clutter_actor_raise (ClutterActor *self,
12331                      ClutterActor *below)
12332 {
12333   ClutterActor *parent;
12334
12335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12336
12337   parent = clutter_actor_get_parent (self);
12338   if (parent == NULL)
12339     {
12340       g_warning ("%s: Actor '%s' is not inside a container",
12341                  G_STRFUNC,
12342                  _clutter_actor_get_debug_name (self));
12343       return;
12344     }
12345
12346   if (below != NULL)
12347     {
12348       if (parent != clutter_actor_get_parent (below))
12349         {
12350           g_warning ("%s Actor '%s' is not in the same container as "
12351                      "actor '%s'",
12352                      G_STRFUNC,
12353                      _clutter_actor_get_debug_name (self),
12354                      _clutter_actor_get_debug_name (below));
12355           return;
12356         }
12357     }
12358
12359   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12360 }
12361
12362 /**
12363  * clutter_actor_lower:
12364  * @self: A #ClutterActor
12365  * @above: (allow-none): A #ClutterActor to lower below
12366  *
12367  * Puts @self below @above.
12368  *
12369  * Both actors must have the same parent, and the parent must implement
12370  * the #ClutterContainer interface.
12371  *
12372  * This function calls clutter_container_lower_child() internally.
12373  *
12374  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12375  */
12376 void
12377 clutter_actor_lower (ClutterActor *self,
12378                      ClutterActor *above)
12379 {
12380   ClutterActor *parent;
12381
12382   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12383
12384   parent = clutter_actor_get_parent (self);
12385   if (parent == NULL)
12386     {
12387       g_warning ("%s: Actor of type %s is not inside a container",
12388                  G_STRFUNC,
12389                  _clutter_actor_get_debug_name (self));
12390       return;
12391     }
12392
12393   if (above)
12394     {
12395       if (parent != clutter_actor_get_parent (above))
12396         {
12397           g_warning ("%s: Actor '%s' is not in the same container as "
12398                      "actor '%s'",
12399                      G_STRFUNC,
12400                      _clutter_actor_get_debug_name (self),
12401                      _clutter_actor_get_debug_name (above));
12402           return;
12403         }
12404     }
12405
12406   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12407 }
12408
12409 /**
12410  * clutter_actor_raise_top:
12411  * @self: A #ClutterActor
12412  *
12413  * Raises @self to the top.
12414  *
12415  * This function calls clutter_actor_raise() internally.
12416  *
12417  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12418  *   a %NULL sibling, instead.
12419  */
12420 void
12421 clutter_actor_raise_top (ClutterActor *self)
12422 {
12423   clutter_actor_raise (self, NULL);
12424 }
12425
12426 /**
12427  * clutter_actor_lower_bottom:
12428  * @self: A #ClutterActor
12429  *
12430  * Lowers @self to the bottom.
12431  *
12432  * This function calls clutter_actor_lower() internally.
12433  *
12434  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12435  *   a %NULL sibling, instead.
12436  */
12437 void
12438 clutter_actor_lower_bottom (ClutterActor *self)
12439 {
12440   clutter_actor_lower (self, NULL);
12441 }
12442
12443 /*
12444  * Event handling
12445  */
12446
12447 /**
12448  * clutter_actor_event:
12449  * @actor: a #ClutterActor
12450  * @event: a #ClutterEvent
12451  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12452  *
12453  * This function is used to emit an event on the main stage.
12454  * You should rarely need to use this function, except for
12455  * synthetising events.
12456  *
12457  * Return value: the return value from the signal emission: %TRUE
12458  *   if the actor handled the event, or %FALSE if the event was
12459  *   not handled
12460  *
12461  * Since: 0.6
12462  */
12463 gboolean
12464 clutter_actor_event (ClutterActor *actor,
12465                      ClutterEvent *event,
12466                      gboolean      capture)
12467 {
12468   gboolean retval = FALSE;
12469   gint signal_num = -1;
12470
12471   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12472   g_return_val_if_fail (event != NULL, FALSE);
12473
12474   g_object_ref (actor);
12475
12476   if (capture)
12477     {
12478       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12479                      event,
12480                      &retval);
12481       goto out;
12482     }
12483
12484   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12485
12486   if (!retval)
12487     {
12488       switch (event->type)
12489         {
12490         case CLUTTER_NOTHING:
12491           break;
12492         case CLUTTER_BUTTON_PRESS:
12493           signal_num = BUTTON_PRESS_EVENT;
12494           break;
12495         case CLUTTER_BUTTON_RELEASE:
12496           signal_num = BUTTON_RELEASE_EVENT;
12497           break;
12498         case CLUTTER_SCROLL:
12499           signal_num = SCROLL_EVENT;
12500           break;
12501         case CLUTTER_KEY_PRESS:
12502           signal_num = KEY_PRESS_EVENT;
12503           break;
12504         case CLUTTER_KEY_RELEASE:
12505           signal_num = KEY_RELEASE_EVENT;
12506           break;
12507         case CLUTTER_MOTION:
12508           signal_num = MOTION_EVENT;
12509           break;
12510         case CLUTTER_ENTER:
12511           signal_num = ENTER_EVENT;
12512           break;
12513         case CLUTTER_LEAVE:
12514           signal_num = LEAVE_EVENT;
12515           break;
12516         case CLUTTER_DELETE:
12517         case CLUTTER_DESTROY_NOTIFY:
12518         case CLUTTER_CLIENT_MESSAGE:
12519         default:
12520           signal_num = -1;
12521           break;
12522         }
12523
12524       if (signal_num != -1)
12525         g_signal_emit (actor, actor_signals[signal_num], 0,
12526                        event, &retval);
12527     }
12528
12529 out:
12530   g_object_unref (actor);
12531
12532   return retval;
12533 }
12534
12535 /**
12536  * clutter_actor_set_reactive:
12537  * @actor: a #ClutterActor
12538  * @reactive: whether the actor should be reactive to events
12539  *
12540  * Sets @actor as reactive. Reactive actors will receive events.
12541  *
12542  * Since: 0.6
12543  */
12544 void
12545 clutter_actor_set_reactive (ClutterActor *actor,
12546                             gboolean      reactive)
12547 {
12548   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12549
12550   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12551     return;
12552
12553   if (reactive)
12554     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12555   else
12556     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12557
12558   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12559 }
12560
12561 /**
12562  * clutter_actor_get_reactive:
12563  * @actor: a #ClutterActor
12564  *
12565  * Checks whether @actor is marked as reactive.
12566  *
12567  * Return value: %TRUE if the actor is reactive
12568  *
12569  * Since: 0.6
12570  */
12571 gboolean
12572 clutter_actor_get_reactive (ClutterActor *actor)
12573 {
12574   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12575
12576   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12577 }
12578
12579 /**
12580  * clutter_actor_get_anchor_point:
12581  * @self: a #ClutterActor
12582  * @anchor_x: (out): return location for the X coordinate of the anchor point
12583  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12584  *
12585  * Gets the current anchor point of the @actor in pixels.
12586  *
12587  * Since: 0.6
12588  */
12589 void
12590 clutter_actor_get_anchor_point (ClutterActor *self,
12591                                 gfloat       *anchor_x,
12592                                 gfloat       *anchor_y)
12593 {
12594   const ClutterTransformInfo *info;
12595
12596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12597
12598   info = _clutter_actor_get_transform_info_or_defaults (self);
12599   clutter_anchor_coord_get_units (self, &info->anchor,
12600                                   anchor_x,
12601                                   anchor_y,
12602                                   NULL);
12603 }
12604
12605 /**
12606  * clutter_actor_set_anchor_point:
12607  * @self: a #ClutterActor
12608  * @anchor_x: X coordinate of the anchor point
12609  * @anchor_y: Y coordinate of the anchor point
12610  *
12611  * Sets an anchor point for @self. The anchor point is a point in the
12612  * coordinate space of an actor to which the actor position within its
12613  * parent is relative; the default is (0, 0), i.e. the top-left corner
12614  * of the actor.
12615  *
12616  * Since: 0.6
12617  */
12618 void
12619 clutter_actor_set_anchor_point (ClutterActor *self,
12620                                 gfloat        anchor_x,
12621                                 gfloat        anchor_y)
12622 {
12623   ClutterTransformInfo *info;
12624   ClutterActorPrivate *priv;
12625   gboolean changed = FALSE;
12626   gfloat old_anchor_x, old_anchor_y;
12627   GObject *obj;
12628
12629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12630
12631   obj = G_OBJECT (self);
12632   priv = self->priv;
12633   info = _clutter_actor_get_transform_info (self);
12634
12635   g_object_freeze_notify (obj);
12636
12637   clutter_anchor_coord_get_units (self, &info->anchor,
12638                                   &old_anchor_x,
12639                                   &old_anchor_y,
12640                                   NULL);
12641
12642   if (info->anchor.is_fractional)
12643     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12644
12645   if (old_anchor_x != anchor_x)
12646     {
12647       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12648       changed = TRUE;
12649     }
12650
12651   if (old_anchor_y != anchor_y)
12652     {
12653       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12654       changed = TRUE;
12655     }
12656
12657   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12658
12659   if (changed)
12660     {
12661       priv->transform_valid = FALSE;
12662       clutter_actor_queue_redraw (self);
12663     }
12664
12665   g_object_thaw_notify (obj);
12666 }
12667
12668 /**
12669  * clutter_actor_get_anchor_point_gravity:
12670  * @self: a #ClutterActor
12671  *
12672  * Retrieves the anchor position expressed as a #ClutterGravity. If
12673  * the anchor point was specified using pixels or units this will
12674  * return %CLUTTER_GRAVITY_NONE.
12675  *
12676  * Return value: the #ClutterGravity used by the anchor point
12677  *
12678  * Since: 1.0
12679  */
12680 ClutterGravity
12681 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12682 {
12683   const ClutterTransformInfo *info;
12684
12685   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12686
12687   info = _clutter_actor_get_transform_info_or_defaults (self);
12688
12689   return clutter_anchor_coord_get_gravity (&info->anchor);
12690 }
12691
12692 /**
12693  * clutter_actor_move_anchor_point:
12694  * @self: a #ClutterActor
12695  * @anchor_x: X coordinate of the anchor point
12696  * @anchor_y: Y coordinate of the anchor point
12697  *
12698  * Sets an anchor point for the actor, and adjusts the actor postion so that
12699  * the relative position of the actor toward its parent remains the same.
12700  *
12701  * Since: 0.6
12702  */
12703 void
12704 clutter_actor_move_anchor_point (ClutterActor *self,
12705                                  gfloat        anchor_x,
12706                                  gfloat        anchor_y)
12707 {
12708   gfloat old_anchor_x, old_anchor_y;
12709   const ClutterTransformInfo *info;
12710
12711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12712
12713   info = _clutter_actor_get_transform_info (self);
12714   clutter_anchor_coord_get_units (self, &info->anchor,
12715                                   &old_anchor_x,
12716                                   &old_anchor_y,
12717                                   NULL);
12718
12719   g_object_freeze_notify (G_OBJECT (self));
12720
12721   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12722
12723   if (self->priv->position_set)
12724     clutter_actor_move_by (self,
12725                            anchor_x - old_anchor_x,
12726                            anchor_y - old_anchor_y);
12727
12728   g_object_thaw_notify (G_OBJECT (self));
12729 }
12730
12731 /**
12732  * clutter_actor_move_anchor_point_from_gravity:
12733  * @self: a #ClutterActor
12734  * @gravity: #ClutterGravity.
12735  *
12736  * Sets an anchor point on the actor based on the given gravity, adjusting the
12737  * actor postion so that its relative position within its parent remains
12738  * unchanged.
12739  *
12740  * Since version 1.0 the anchor point will be stored as a gravity so
12741  * that if the actor changes size then the anchor point will move. For
12742  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12743  * and later double the size of the actor, the anchor point will move
12744  * to the bottom right.
12745  *
12746  * Since: 0.6
12747  */
12748 void
12749 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12750                                               ClutterGravity  gravity)
12751 {
12752   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12753   const ClutterTransformInfo *info;
12754   ClutterActorPrivate *priv;
12755
12756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12757
12758   priv = self->priv;
12759   info = _clutter_actor_get_transform_info (self);
12760
12761   g_object_freeze_notify (G_OBJECT (self));
12762
12763   clutter_anchor_coord_get_units (self, &info->anchor,
12764                                   &old_anchor_x,
12765                                   &old_anchor_y,
12766                                   NULL);
12767   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12768   clutter_anchor_coord_get_units (self, &info->anchor,
12769                                   &new_anchor_x,
12770                                   &new_anchor_y,
12771                                   NULL);
12772
12773   if (priv->position_set)
12774     clutter_actor_move_by (self,
12775                            new_anchor_x - old_anchor_x,
12776                            new_anchor_y - old_anchor_y);
12777
12778   g_object_thaw_notify (G_OBJECT (self));
12779 }
12780
12781 /**
12782  * clutter_actor_set_anchor_point_from_gravity:
12783  * @self: a #ClutterActor
12784  * @gravity: #ClutterGravity.
12785  *
12786  * Sets an anchor point on the actor, based on the given gravity (this is a
12787  * convenience function wrapping clutter_actor_set_anchor_point()).
12788  *
12789  * Since version 1.0 the anchor point will be stored as a gravity so
12790  * that if the actor changes size then the anchor point will move. For
12791  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12792  * and later double the size of the actor, the anchor point will move
12793  * to the bottom right.
12794  *
12795  * Since: 0.6
12796  */
12797 void
12798 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12799                                              ClutterGravity  gravity)
12800 {
12801   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12802
12803   if (gravity == CLUTTER_GRAVITY_NONE)
12804     clutter_actor_set_anchor_point (self, 0, 0);
12805   else
12806     {
12807       GObject *obj = G_OBJECT (self);
12808       ClutterTransformInfo *info;
12809
12810       g_object_freeze_notify (obj);
12811
12812       info = _clutter_actor_get_transform_info (self);
12813       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12814
12815       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12816       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12817       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12818
12819       self->priv->transform_valid = FALSE;
12820
12821       clutter_actor_queue_redraw (self);
12822
12823       g_object_thaw_notify (obj);
12824     }
12825 }
12826
12827 static void
12828 clutter_actor_store_content_box (ClutterActor *self,
12829                                  const ClutterActorBox *box)
12830 {
12831   if (box != NULL)
12832     {
12833       self->priv->content_box = *box;
12834       self->priv->content_box_valid = TRUE;
12835     }
12836   else
12837     self->priv->content_box_valid = FALSE;
12838
12839   clutter_actor_queue_redraw (self);
12840
12841   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12842 }
12843
12844 static void
12845 clutter_container_iface_init (ClutterContainerIface *iface)
12846 {
12847   /* we don't override anything, as ClutterContainer already has a default
12848    * implementation that we can use, and which calls into our own API.
12849    */
12850 }
12851
12852 typedef enum
12853 {
12854   PARSE_X,
12855   PARSE_Y,
12856   PARSE_WIDTH,
12857   PARSE_HEIGHT,
12858   PARSE_ANCHOR_X,
12859   PARSE_ANCHOR_Y
12860 } ParseDimension;
12861
12862 static gfloat
12863 parse_units (ClutterActor   *self,
12864              ParseDimension  dimension,
12865              JsonNode       *node)
12866 {
12867   GValue value = G_VALUE_INIT;
12868   gfloat retval = 0;
12869
12870   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12871     return 0;
12872
12873   json_node_get_value (node, &value);
12874
12875   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12876     {
12877       retval = (gfloat) g_value_get_int64 (&value);
12878     }
12879   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12880     {
12881       retval = g_value_get_double (&value);
12882     }
12883   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12884     {
12885       ClutterUnits units;
12886       gboolean res;
12887
12888       res = clutter_units_from_string (&units, g_value_get_string (&value));
12889       if (res)
12890         retval = clutter_units_to_pixels (&units);
12891       else
12892         {
12893           g_warning ("Invalid value '%s': integers, strings or floating point "
12894                      "values can be used for the x, y, width and height "
12895                      "properties. Valid modifiers for strings are 'px', 'mm', "
12896                      "'pt' and 'em'.",
12897                      g_value_get_string (&value));
12898           retval = 0;
12899         }
12900     }
12901   else
12902     {
12903       g_warning ("Invalid value of type '%s': integers, strings of floating "
12904                  "point values can be used for the x, y, width, height "
12905                  "anchor-x and anchor-y properties.",
12906                  g_type_name (G_VALUE_TYPE (&value)));
12907     }
12908
12909   g_value_unset (&value);
12910
12911   return retval;
12912 }
12913
12914 typedef struct {
12915   ClutterRotateAxis axis;
12916
12917   gdouble angle;
12918
12919   gfloat center_x;
12920   gfloat center_y;
12921   gfloat center_z;
12922 } RotationInfo;
12923
12924 static inline gboolean
12925 parse_rotation_array (ClutterActor *actor,
12926                       JsonArray    *array,
12927                       RotationInfo *info)
12928 {
12929   JsonNode *element;
12930
12931   if (json_array_get_length (array) != 2)
12932     return FALSE;
12933
12934   /* angle */
12935   element = json_array_get_element (array, 0);
12936   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12937     info->angle = json_node_get_double (element);
12938   else
12939     return FALSE;
12940
12941   /* center */
12942   element = json_array_get_element (array, 1);
12943   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12944     {
12945       JsonArray *center = json_node_get_array (element);
12946
12947       if (json_array_get_length (center) != 2)
12948         return FALSE;
12949
12950       switch (info->axis)
12951         {
12952         case CLUTTER_X_AXIS:
12953           info->center_y = parse_units (actor, PARSE_Y,
12954                                         json_array_get_element (center, 0));
12955           info->center_z = parse_units (actor, PARSE_Y,
12956                                         json_array_get_element (center, 1));
12957           return TRUE;
12958
12959         case CLUTTER_Y_AXIS:
12960           info->center_x = parse_units (actor, PARSE_X,
12961                                         json_array_get_element (center, 0));
12962           info->center_z = parse_units (actor, PARSE_X,
12963                                         json_array_get_element (center, 1));
12964           return TRUE;
12965
12966         case CLUTTER_Z_AXIS:
12967           info->center_x = parse_units (actor, PARSE_X,
12968                                         json_array_get_element (center, 0));
12969           info->center_y = parse_units (actor, PARSE_Y,
12970                                         json_array_get_element (center, 1));
12971           return TRUE;
12972         }
12973     }
12974
12975   return FALSE;
12976 }
12977
12978 static gboolean
12979 parse_rotation (ClutterActor *actor,
12980                 JsonNode     *node,
12981                 RotationInfo *info)
12982 {
12983   JsonArray *array;
12984   guint len, i;
12985   gboolean retval = FALSE;
12986
12987   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12988     {
12989       g_warning ("Invalid node of type '%s' found, expecting an array",
12990                  json_node_type_name (node));
12991       return FALSE;
12992     }
12993
12994   array = json_node_get_array (node);
12995   len = json_array_get_length (array);
12996
12997   for (i = 0; i < len; i++)
12998     {
12999       JsonNode *element = json_array_get_element (array, i);
13000       JsonObject *object;
13001       JsonNode *member;
13002
13003       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
13004         {
13005           g_warning ("Invalid node of type '%s' found, expecting an object",
13006                      json_node_type_name (element));
13007           return FALSE;
13008         }
13009
13010       object = json_node_get_object (element);
13011
13012       if (json_object_has_member (object, "x-axis"))
13013         {
13014           member = json_object_get_member (object, "x-axis");
13015
13016           info->axis = CLUTTER_X_AXIS;
13017
13018           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13019             {
13020               info->angle = json_node_get_double (member);
13021               retval = TRUE;
13022             }
13023           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13024             retval = parse_rotation_array (actor,
13025                                            json_node_get_array (member),
13026                                            info);
13027           else
13028             retval = FALSE;
13029         }
13030       else if (json_object_has_member (object, "y-axis"))
13031         {
13032           member = json_object_get_member (object, "y-axis");
13033
13034           info->axis = CLUTTER_Y_AXIS;
13035
13036           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13037             {
13038               info->angle = json_node_get_double (member);
13039               retval = TRUE;
13040             }
13041           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13042             retval = parse_rotation_array (actor,
13043                                            json_node_get_array (member),
13044                                            info);
13045           else
13046             retval = FALSE;
13047         }
13048       else if (json_object_has_member (object, "z-axis"))
13049         {
13050           member = json_object_get_member (object, "z-axis");
13051
13052           info->axis = CLUTTER_Z_AXIS;
13053
13054           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13055             {
13056               info->angle = json_node_get_double (member);
13057               retval = TRUE;
13058             }
13059           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13060             retval = parse_rotation_array (actor,
13061                                            json_node_get_array (member),
13062                                            info);
13063           else
13064             retval = FALSE;
13065         }
13066     }
13067
13068   return retval;
13069 }
13070
13071 static GSList *
13072 parse_actor_metas (ClutterScript *script,
13073                    ClutterActor  *actor,
13074                    JsonNode      *node)
13075 {
13076   GList *elements, *l;
13077   GSList *retval = NULL;
13078
13079   if (!JSON_NODE_HOLDS_ARRAY (node))
13080     return NULL;
13081
13082   elements = json_array_get_elements (json_node_get_array (node));
13083
13084   for (l = elements; l != NULL; l = l->next)
13085     {
13086       JsonNode *element = l->data;
13087       const gchar *id_ = _clutter_script_get_id_from_node (element);
13088       GObject *meta;
13089
13090       if (id_ == NULL || *id_ == '\0')
13091         continue;
13092
13093       meta = clutter_script_get_object (script, id_);
13094       if (meta == NULL)
13095         continue;
13096
13097       retval = g_slist_prepend (retval, meta);
13098     }
13099
13100   g_list_free (elements);
13101
13102   return g_slist_reverse (retval);
13103 }
13104
13105 static GSList *
13106 parse_behaviours (ClutterScript *script,
13107                   ClutterActor  *actor,
13108                   JsonNode      *node)
13109 {
13110   GList *elements, *l;
13111   GSList *retval = NULL;
13112
13113   if (!JSON_NODE_HOLDS_ARRAY (node))
13114     return NULL;
13115
13116   elements = json_array_get_elements (json_node_get_array (node));
13117
13118   for (l = elements; l != NULL; l = l->next)
13119     {
13120       JsonNode *element = l->data;
13121       const gchar *id_ = _clutter_script_get_id_from_node (element);
13122       GObject *behaviour;
13123
13124       if (id_ == NULL || *id_ == '\0')
13125         continue;
13126
13127       behaviour = clutter_script_get_object (script, id_);
13128       if (behaviour == NULL)
13129         continue;
13130
13131       retval = g_slist_prepend (retval, behaviour);
13132     }
13133
13134   g_list_free (elements);
13135
13136   return g_slist_reverse (retval);
13137 }
13138
13139 static ClutterMargin *
13140 parse_margin (ClutterActor *self,
13141               JsonNode     *node)
13142 {
13143   ClutterMargin *margin;
13144   JsonArray *array;
13145
13146   if (!JSON_NODE_HOLDS_ARRAY (node))
13147     {
13148       g_warning ("The margin property must be an array of 1 to 4 elements");
13149       return NULL;
13150     }
13151
13152   margin = clutter_margin_new ();
13153   array = json_node_get_array (node);
13154   switch (json_array_get_length (array))
13155     {
13156     case 1:
13157       margin->top = margin->right = margin->bottom = margin->left =
13158         parse_units (self, 0, json_array_get_element (array, 0));
13159       break;
13160
13161     case 2:
13162       margin->top = margin->bottom =
13163         parse_units (self, 0, json_array_get_element (array, 0));
13164       margin->right = margin->left =
13165         parse_units (self, 0, json_array_get_element (array, 1));
13166       break;
13167
13168     case 3:
13169       margin->top =
13170         parse_units (self, 0, json_array_get_element (array, 0));
13171       margin->right = margin->left =
13172         parse_units (self, 0, json_array_get_element (array, 1));
13173       margin->bottom =
13174         parse_units (self, 0, json_array_get_element (array, 2));
13175       break;
13176
13177     case 4:
13178       margin->top =
13179         parse_units (self, 0, json_array_get_element (array, 0));
13180       margin->right =
13181         parse_units (self, 0, json_array_get_element (array, 1));
13182       margin->bottom =
13183         parse_units (self, 0, json_array_get_element (array, 2));
13184       margin->left =
13185         parse_units (self, 0, json_array_get_element (array, 3));
13186       break;
13187
13188     default:
13189       g_warning ("The margin property must be an array of 1 to 4 elements");
13190       clutter_margin_free (margin);
13191       return NULL;
13192     }
13193   return margin;
13194 }
13195
13196 static gboolean
13197 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13198                                  ClutterScript     *script,
13199                                  GValue            *value,
13200                                  const gchar       *name,
13201                                  JsonNode          *node)
13202 {
13203   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13204   gboolean retval = FALSE;
13205
13206   if ((name[0] == 'x' && name[1] == '\0') ||
13207       (name[0] == 'y' && name[1] == '\0') ||
13208       (strcmp (name, "width") == 0) ||
13209       (strcmp (name, "height") == 0) ||
13210       (strcmp (name, "anchor_x") == 0) ||
13211       (strcmp (name, "anchor_y") == 0))
13212     {
13213       ParseDimension dimension;
13214       gfloat units;
13215
13216       if (name[0] == 'x')
13217         dimension = PARSE_X;
13218       else if (name[0] == 'y')
13219         dimension = PARSE_Y;
13220       else if (name[0] == 'w')
13221         dimension = PARSE_WIDTH;
13222       else if (name[0] == 'h')
13223         dimension = PARSE_HEIGHT;
13224       else if (name[0] == 'a' && name[7] == 'x')
13225         dimension = PARSE_ANCHOR_X;
13226       else if (name[0] == 'a' && name[7] == 'y')
13227         dimension = PARSE_ANCHOR_Y;
13228       else
13229         return FALSE;
13230
13231       units = parse_units (actor, dimension, node);
13232
13233       /* convert back to pixels: all properties are pixel-based */
13234       g_value_init (value, G_TYPE_FLOAT);
13235       g_value_set_float (value, units);
13236
13237       retval = TRUE;
13238     }
13239   else if (strcmp (name, "rotation") == 0)
13240     {
13241       RotationInfo *info;
13242
13243       info = g_slice_new0 (RotationInfo);
13244       retval = parse_rotation (actor, node, info);
13245
13246       if (retval)
13247         {
13248           g_value_init (value, G_TYPE_POINTER);
13249           g_value_set_pointer (value, info);
13250         }
13251       else
13252         g_slice_free (RotationInfo, info);
13253     }
13254   else if (strcmp (name, "behaviours") == 0)
13255     {
13256       GSList *l;
13257
13258 #ifdef CLUTTER_ENABLE_DEBUG
13259       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13260         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13261                                      "and it should not be used in newly "
13262                                      "written ClutterScript definitions.");
13263 #endif
13264
13265       l = parse_behaviours (script, actor, node);
13266
13267       g_value_init (value, G_TYPE_POINTER);
13268       g_value_set_pointer (value, l);
13269
13270       retval = TRUE;
13271     }
13272   else if (strcmp (name, "actions") == 0 ||
13273            strcmp (name, "constraints") == 0 ||
13274            strcmp (name, "effects") == 0)
13275     {
13276       GSList *l;
13277
13278       l = parse_actor_metas (script, actor, node);
13279
13280       g_value_init (value, G_TYPE_POINTER);
13281       g_value_set_pointer (value, l);
13282
13283       retval = TRUE;
13284     }
13285   else if (strcmp (name, "margin") == 0)
13286     {
13287       ClutterMargin *margin = parse_margin (actor, node);
13288
13289       if (margin)
13290         {
13291           g_value_init (value, CLUTTER_TYPE_MARGIN);
13292           g_value_set_boxed (value, margin);
13293           retval = TRUE;
13294         }
13295     }
13296
13297   return retval;
13298 }
13299
13300 static void
13301 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13302                                    ClutterScript     *script,
13303                                    const gchar       *name,
13304                                    const GValue      *value)
13305 {
13306   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13307
13308 #ifdef CLUTTER_ENABLE_DEBUG
13309   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13310     {
13311       gchar *tmp = g_strdup_value_contents (value);
13312
13313       CLUTTER_NOTE (SCRIPT,
13314                     "in ClutterActor::set_custom_property('%s') = %s",
13315                     name,
13316                     tmp);
13317
13318       g_free (tmp);
13319     }
13320 #endif /* CLUTTER_ENABLE_DEBUG */
13321
13322   if (strcmp (name, "rotation") == 0)
13323     {
13324       RotationInfo *info;
13325
13326       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13327         return;
13328
13329       info = g_value_get_pointer (value);
13330
13331       clutter_actor_set_rotation (actor,
13332                                   info->axis, info->angle,
13333                                   info->center_x,
13334                                   info->center_y,
13335                                   info->center_z);
13336
13337       g_slice_free (RotationInfo, info);
13338
13339       return;
13340     }
13341
13342   if (strcmp (name, "behaviours") == 0)
13343     {
13344       GSList *behaviours, *l;
13345
13346       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13347         return;
13348
13349       behaviours = g_value_get_pointer (value);
13350       for (l = behaviours; l != NULL; l = l->next)
13351         {
13352           ClutterBehaviour *behaviour = l->data;
13353
13354           clutter_behaviour_apply (behaviour, actor);
13355         }
13356
13357       g_slist_free (behaviours);
13358
13359       return;
13360     }
13361
13362   if (strcmp (name, "actions") == 0 ||
13363       strcmp (name, "constraints") == 0 ||
13364       strcmp (name, "effects") == 0)
13365     {
13366       GSList *metas, *l;
13367
13368       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13369         return;
13370
13371       metas = g_value_get_pointer (value);
13372       for (l = metas; l != NULL; l = l->next)
13373         {
13374           if (name[0] == 'a')
13375             clutter_actor_add_action (actor, l->data);
13376
13377           if (name[0] == 'c')
13378             clutter_actor_add_constraint (actor, l->data);
13379
13380           if (name[0] == 'e')
13381             clutter_actor_add_effect (actor, l->data);
13382         }
13383
13384       g_slist_free (metas);
13385
13386       return;
13387     }
13388   if (strcmp (name, "margin") == 0)
13389     {
13390       clutter_actor_set_margin (actor, g_value_get_boxed (value));
13391       return;
13392     }
13393
13394   g_object_set_property (G_OBJECT (scriptable), name, value);
13395 }
13396
13397 static void
13398 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13399 {
13400   iface->parse_custom_node = clutter_actor_parse_custom_node;
13401   iface->set_custom_property = clutter_actor_set_custom_property;
13402 }
13403
13404 static ClutterActorMeta *
13405 get_meta_from_animation_property (ClutterActor  *actor,
13406                                   const gchar   *name,
13407                                   gchar        **name_p)
13408 {
13409   ClutterActorPrivate *priv = actor->priv;
13410   ClutterActorMeta *meta = NULL;
13411   gchar **tokens;
13412
13413   /* if this is not a special property, fall through */
13414   if (name[0] != '@')
13415     return NULL;
13416
13417   /* detect the properties named using the following spec:
13418    *
13419    *   @<section>.<meta-name>.<property-name>
13420    *
13421    * where <section> can be one of the following:
13422    *
13423    *   - actions
13424    *   - constraints
13425    *   - effects
13426    *
13427    * and <meta-name> is the name set on a specific ActorMeta
13428    */
13429
13430   tokens = g_strsplit (name + 1, ".", -1);
13431   if (tokens == NULL || g_strv_length (tokens) != 3)
13432     {
13433       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13434                     name + 1);
13435       g_strfreev (tokens);
13436       return NULL;
13437     }
13438
13439   if (strcmp (tokens[0], "actions") == 0)
13440     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13441
13442   if (strcmp (tokens[0], "constraints") == 0)
13443     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13444
13445   if (strcmp (tokens[0], "effects") == 0)
13446     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13447
13448   if (name_p != NULL)
13449     *name_p = g_strdup (tokens[2]);
13450
13451   CLUTTER_NOTE (ANIMATION,
13452                 "Looking for property '%s' of object '%s' in section '%s'",
13453                 tokens[2],
13454                 tokens[1],
13455                 tokens[0]);
13456
13457   g_strfreev (tokens);
13458
13459   return meta;
13460 }
13461
13462 static GParamSpec *
13463 clutter_actor_find_property (ClutterAnimatable *animatable,
13464                              const gchar       *property_name)
13465 {
13466   ClutterActorMeta *meta = NULL;
13467   GObjectClass *klass = NULL;
13468   GParamSpec *pspec = NULL;
13469   gchar *p_name = NULL;
13470
13471   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13472                                            property_name,
13473                                            &p_name);
13474
13475   if (meta != NULL)
13476     {
13477       klass = G_OBJECT_GET_CLASS (meta);
13478
13479       pspec = g_object_class_find_property (klass, p_name);
13480     }
13481   else
13482     {
13483       klass = G_OBJECT_GET_CLASS (animatable);
13484
13485       pspec = g_object_class_find_property (klass, property_name);
13486     }
13487
13488   g_free (p_name);
13489
13490   return pspec;
13491 }
13492
13493 static void
13494 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13495                                  const gchar       *property_name,
13496                                  GValue            *initial)
13497 {
13498   ClutterActorMeta *meta = NULL;
13499   gchar *p_name = NULL;
13500
13501   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13502                                            property_name,
13503                                            &p_name);
13504
13505   if (meta != NULL)
13506     g_object_get_property (G_OBJECT (meta), p_name, initial);
13507   else
13508     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13509
13510   g_free (p_name);
13511 }
13512
13513 /*
13514  * clutter_actor_set_animatable_property:
13515  * @actor: a #ClutterActor
13516  * @prop_id: the paramspec id
13517  * @value: the value to set
13518  * @pspec: the paramspec
13519  *
13520  * Sets values of animatable properties.
13521  *
13522  * This is a variant of clutter_actor_set_property() that gets called
13523  * by the #ClutterAnimatable implementation of #ClutterActor for the
13524  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13525  * #GParamSpec.
13526  *
13527  * Unlike the implementation of #GObjectClass.set_property(), this
13528  * function will not update the interval if a transition involving an
13529  * animatable property is in progress - this avoids cycles with the
13530  * transition API calling the public API.
13531  */
13532 static void
13533 clutter_actor_set_animatable_property (ClutterActor *actor,
13534                                        guint         prop_id,
13535                                        const GValue *value,
13536                                        GParamSpec   *pspec)
13537 {
13538   GObject *obj = G_OBJECT (actor);
13539
13540   g_object_freeze_notify (obj);
13541
13542   switch (prop_id)
13543     {
13544     case PROP_X:
13545       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13546       break;
13547
13548     case PROP_Y:
13549       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13550       break;
13551
13552     case PROP_POSITION:
13553       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13554       break;
13555
13556     case PROP_WIDTH:
13557       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13558       break;
13559
13560     case PROP_HEIGHT:
13561       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13562       break;
13563
13564     case PROP_SIZE:
13565       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13566       break;
13567
13568     case PROP_ALLOCATION:
13569       clutter_actor_allocate_internal (actor,
13570                                        g_value_get_boxed (value),
13571                                        actor->priv->allocation_flags);
13572       break;
13573
13574     case PROP_DEPTH:
13575       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13576       break;
13577
13578     case PROP_OPACITY:
13579       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13580       break;
13581
13582     case PROP_BACKGROUND_COLOR:
13583       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13584       break;
13585
13586     case PROP_SCALE_X:
13587       clutter_actor_set_scale_factor_internal (actor,
13588                                                g_value_get_double (value),
13589                                                pspec);
13590       break;
13591
13592     case PROP_SCALE_Y:
13593       clutter_actor_set_scale_factor_internal (actor,
13594                                                g_value_get_double (value),
13595                                                pspec);
13596       break;
13597
13598     case PROP_ROTATION_ANGLE_X:
13599       clutter_actor_set_rotation_angle_internal (actor,
13600                                                  CLUTTER_X_AXIS,
13601                                                  g_value_get_double (value));
13602       break;
13603
13604     case PROP_ROTATION_ANGLE_Y:
13605       clutter_actor_set_rotation_angle_internal (actor,
13606                                                  CLUTTER_Y_AXIS,
13607                                                  g_value_get_double (value));
13608       break;
13609
13610     case PROP_ROTATION_ANGLE_Z:
13611       clutter_actor_set_rotation_angle_internal (actor,
13612                                                  CLUTTER_Z_AXIS,
13613                                                  g_value_get_double (value));
13614       break;
13615
13616     case PROP_CONTENT_BOX:
13617       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13618       break;
13619
13620     default:
13621       g_object_set_property (obj, pspec->name, value);
13622       break;
13623     }
13624
13625   g_object_thaw_notify (obj);
13626 }
13627
13628 static void
13629 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13630                                const gchar       *property_name,
13631                                const GValue      *final)
13632 {
13633   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13634   ClutterActorMeta *meta = NULL;
13635   gchar *p_name = NULL;
13636
13637   meta = get_meta_from_animation_property (actor,
13638                                            property_name,
13639                                            &p_name);
13640   if (meta != NULL)
13641     g_object_set_property (G_OBJECT (meta), p_name, final);
13642   else
13643     {
13644       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13645       GParamSpec *pspec;
13646
13647       pspec = g_object_class_find_property (obj_class, property_name);
13648
13649       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13650         {
13651           /* XXX - I'm going to the special hell for this */
13652           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13653         }
13654       else
13655         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13656     }
13657
13658   g_free (p_name);
13659 }
13660
13661 static void
13662 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13663 {
13664   iface->find_property = clutter_actor_find_property;
13665   iface->get_initial_state = clutter_actor_get_initial_state;
13666   iface->set_final_state = clutter_actor_set_final_state;
13667 }
13668
13669 /**
13670  * clutter_actor_transform_stage_point:
13671  * @self: A #ClutterActor
13672  * @x: (in): x screen coordinate of the point to unproject
13673  * @y: (in): y screen coordinate of the point to unproject
13674  * @x_out: (out): return location for the unprojected x coordinance
13675  * @y_out: (out): return location for the unprojected y coordinance
13676  *
13677  * This function translates screen coordinates (@x, @y) to
13678  * coordinates relative to the actor. For example, it can be used to translate
13679  * screen events from global screen coordinates into actor-local coordinates.
13680  *
13681  * The conversion can fail, notably if the transform stack results in the
13682  * actor being projected on the screen as a mere line.
13683  *
13684  * The conversion should not be expected to be pixel-perfect due to the
13685  * nature of the operation. In general the error grows when the skewing
13686  * of the actor rectangle on screen increases.
13687  *
13688  * <note><para>This function can be computationally intensive.</para></note>
13689  *
13690  * <note><para>This function only works when the allocation is up-to-date,
13691  * i.e. inside of paint().</para></note>
13692  *
13693  * Return value: %TRUE if conversion was successful.
13694  *
13695  * Since: 0.6
13696  */
13697 gboolean
13698 clutter_actor_transform_stage_point (ClutterActor *self,
13699                                      gfloat        x,
13700                                      gfloat        y,
13701                                      gfloat       *x_out,
13702                                      gfloat       *y_out)
13703 {
13704   ClutterVertex v[4];
13705   float ST[3][3];
13706   float RQ[3][3];
13707   int du, dv, xi, yi;
13708   float px, py;
13709   float xf, yf, wf, det;
13710   ClutterActorPrivate *priv;
13711
13712   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13713
13714   priv = self->priv;
13715
13716   /* This implementation is based on the quad -> quad projection algorithm
13717    * described by Paul Heckbert in:
13718    *
13719    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13720    *
13721    * and the sample implementation at:
13722    *
13723    *   http://www.cs.cmu.edu/~ph/src/texfund/
13724    *
13725    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13726    * quad to rectangle only, which significantly simplifies things; the
13727    * function calls have been unrolled, and most of the math is done in fixed
13728    * point.
13729    */
13730
13731   clutter_actor_get_abs_allocation_vertices (self, v);
13732
13733   /* Keeping these as ints simplifies the multiplication (no significant
13734    * loss of precision here).
13735    */
13736   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13737   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13738
13739   if (!du || !dv)
13740     return FALSE;
13741
13742 #define UX2FP(x)        (x)
13743 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13744
13745   /* First, find mapping from unit uv square to xy quadrilateral; this
13746    * equivalent to the pmap_square_quad() functions in the sample
13747    * implementation, which we can simplify, since our target is always
13748    * a rectangle.
13749    */
13750   px = v[0].x - v[1].x + v[3].x - v[2].x;
13751   py = v[0].y - v[1].y + v[3].y - v[2].y;
13752
13753   if (!px && !py)
13754     {
13755       /* affine transform */
13756       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13757       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13758       RQ[2][0] = UX2FP (v[0].x);
13759       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13760       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13761       RQ[2][1] = UX2FP (v[0].y);
13762       RQ[0][2] = 0;
13763       RQ[1][2] = 0;
13764       RQ[2][2] = 1.0;
13765     }
13766   else
13767     {
13768       /* projective transform */
13769       double dx1, dx2, dy1, dy2, del;
13770
13771       dx1 = UX2FP (v[1].x - v[3].x);
13772       dx2 = UX2FP (v[2].x - v[3].x);
13773       dy1 = UX2FP (v[1].y - v[3].y);
13774       dy2 = UX2FP (v[2].y - v[3].y);
13775
13776       del = DET2FP (dx1, dx2, dy1, dy2);
13777       if (!del)
13778         return FALSE;
13779
13780       /*
13781        * The division here needs to be done in floating point for
13782        * precisions reasons.
13783        */
13784       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13785       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13786       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13787       RQ[2][2] = 1.0;
13788       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13789       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13790       RQ[2][0] = UX2FP (v[0].x);
13791       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13792       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13793       RQ[2][1] = UX2FP (v[0].y);
13794     }
13795
13796   /*
13797    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13798    * square. Since our rectangle is based at 0,0 we only need to scale.
13799    */
13800   RQ[0][0] /= du;
13801   RQ[1][0] /= dv;
13802   RQ[0][1] /= du;
13803   RQ[1][1] /= dv;
13804   RQ[0][2] /= du;
13805   RQ[1][2] /= dv;
13806
13807   /*
13808    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13809    * inverse of that.
13810    */
13811   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13812   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13813   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13814   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13815   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13816   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13817   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13818   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13819   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13820
13821   /*
13822    * Check the resulting matrix is OK.
13823    */
13824   det = (RQ[0][0] * ST[0][0])
13825       + (RQ[0][1] * ST[0][1])
13826       + (RQ[0][2] * ST[0][2]);
13827   if (!det)
13828     return FALSE;
13829
13830   /*
13831    * Now transform our point with the ST matrix; the notional w
13832    * coordinate is 1, hence the last part is simply added.
13833    */
13834   xi = (int) x;
13835   yi = (int) y;
13836
13837   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13838   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13839   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13840
13841   if (x_out)
13842     *x_out = xf / wf;
13843
13844   if (y_out)
13845     *y_out = yf / wf;
13846
13847 #undef UX2FP
13848 #undef DET2FP
13849
13850   return TRUE;
13851 }
13852
13853 /**
13854  * clutter_actor_is_rotated:
13855  * @self: a #ClutterActor
13856  *
13857  * Checks whether any rotation is applied to the actor.
13858  *
13859  * Return value: %TRUE if the actor is rotated.
13860  *
13861  * Since: 0.6
13862  */
13863 gboolean
13864 clutter_actor_is_rotated (ClutterActor *self)
13865 {
13866   const ClutterTransformInfo *info;
13867
13868   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13869
13870   info = _clutter_actor_get_transform_info_or_defaults (self);
13871
13872   if (info->rx_angle || info->ry_angle || info->rz_angle)
13873     return TRUE;
13874
13875   return FALSE;
13876 }
13877
13878 /**
13879  * clutter_actor_is_scaled:
13880  * @self: a #ClutterActor
13881  *
13882  * Checks whether the actor is scaled in either dimension.
13883  *
13884  * Return value: %TRUE if the actor is scaled.
13885  *
13886  * Since: 0.6
13887  */
13888 gboolean
13889 clutter_actor_is_scaled (ClutterActor *self)
13890 {
13891   const ClutterTransformInfo *info;
13892
13893   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13894
13895   info = _clutter_actor_get_transform_info_or_defaults (self);
13896
13897   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13898     return TRUE;
13899
13900   return FALSE;
13901 }
13902
13903 ClutterActor *
13904 _clutter_actor_get_stage_internal (ClutterActor *actor)
13905 {
13906   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13907     actor = actor->priv->parent;
13908
13909   return actor;
13910 }
13911
13912 /**
13913  * clutter_actor_get_stage:
13914  * @actor: a #ClutterActor
13915  *
13916  * Retrieves the #ClutterStage where @actor is contained.
13917  *
13918  * Return value: (transfer none) (type Clutter.Stage): the stage
13919  *   containing the actor, or %NULL
13920  *
13921  * Since: 0.8
13922  */
13923 ClutterActor *
13924 clutter_actor_get_stage (ClutterActor *actor)
13925 {
13926   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13927
13928   return _clutter_actor_get_stage_internal (actor);
13929 }
13930
13931 /**
13932  * clutter_actor_allocate_available_size:
13933  * @self: a #ClutterActor
13934  * @x: the actor's X coordinate
13935  * @y: the actor's Y coordinate
13936  * @available_width: the maximum available width, or -1 to use the
13937  *   actor's natural width
13938  * @available_height: the maximum available height, or -1 to use the
13939  *   actor's natural height
13940  * @flags: flags controlling the allocation
13941  *
13942  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13943  * preferred size, but limiting it to the maximum available width
13944  * and height provided.
13945  *
13946  * This function will do the right thing when dealing with the
13947  * actor's request mode.
13948  *
13949  * The implementation of this function is equivalent to:
13950  *
13951  * |[
13952  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13953  *     {
13954  *       clutter_actor_get_preferred_width (self, available_height,
13955  *                                          &amp;min_width,
13956  *                                          &amp;natural_width);
13957  *       width = CLAMP (natural_width, min_width, available_width);
13958  *
13959  *       clutter_actor_get_preferred_height (self, width,
13960  *                                           &amp;min_height,
13961  *                                           &amp;natural_height);
13962  *       height = CLAMP (natural_height, min_height, available_height);
13963  *     }
13964  *   else
13965  *     {
13966  *       clutter_actor_get_preferred_height (self, available_width,
13967  *                                           &amp;min_height,
13968  *                                           &amp;natural_height);
13969  *       height = CLAMP (natural_height, min_height, available_height);
13970  *
13971  *       clutter_actor_get_preferred_width (self, height,
13972  *                                          &amp;min_width,
13973  *                                          &amp;natural_width);
13974  *       width = CLAMP (natural_width, min_width, available_width);
13975  *     }
13976  *
13977  *   box.x1 = x; box.y1 = y;
13978  *   box.x2 = box.x1 + available_width;
13979  *   box.y2 = box.y1 + available_height;
13980  *   clutter_actor_allocate (self, &amp;box, flags);
13981  * ]|
13982  *
13983  * This function can be used by fluid layout managers to allocate
13984  * an actor's preferred size without making it bigger than the area
13985  * available for the container.
13986  *
13987  * Since: 1.0
13988  */
13989 void
13990 clutter_actor_allocate_available_size (ClutterActor           *self,
13991                                        gfloat                  x,
13992                                        gfloat                  y,
13993                                        gfloat                  available_width,
13994                                        gfloat                  available_height,
13995                                        ClutterAllocationFlags  flags)
13996 {
13997   ClutterActorPrivate *priv;
13998   gfloat width, height;
13999   gfloat min_width, min_height;
14000   gfloat natural_width, natural_height;
14001   ClutterActorBox box;
14002
14003   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14004
14005   priv = self->priv;
14006
14007   width = height = 0.0;
14008
14009   switch (priv->request_mode)
14010     {
14011     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
14012       clutter_actor_get_preferred_width (self, available_height,
14013                                          &min_width,
14014                                          &natural_width);
14015       width  = CLAMP (natural_width, min_width, available_width);
14016
14017       clutter_actor_get_preferred_height (self, width,
14018                                           &min_height,
14019                                           &natural_height);
14020       height = CLAMP (natural_height, min_height, available_height);
14021       break;
14022
14023     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
14024       clutter_actor_get_preferred_height (self, available_width,
14025                                           &min_height,
14026                                           &natural_height);
14027       height = CLAMP (natural_height, min_height, available_height);
14028
14029       clutter_actor_get_preferred_width (self, height,
14030                                          &min_width,
14031                                          &natural_width);
14032       width  = CLAMP (natural_width, min_width, available_width);
14033       break;
14034     }
14035
14036
14037   box.x1 = x;
14038   box.y1 = y;
14039   box.x2 = box.x1 + width;
14040   box.y2 = box.y1 + height;
14041   clutter_actor_allocate (self, &box, flags);
14042 }
14043
14044 /**
14045  * clutter_actor_allocate_preferred_size:
14046  * @self: a #ClutterActor
14047  * @flags: flags controlling the allocation
14048  *
14049  * Allocates the natural size of @self.
14050  *
14051  * This function is a utility call for #ClutterActor implementations
14052  * that allocates the actor's preferred natural size. It can be used
14053  * by fixed layout managers (like #ClutterGroup or so called
14054  * 'composite actors') inside the ClutterActor::allocate
14055  * implementation to give each child exactly how much space it
14056  * requires.
14057  *
14058  * This function is not meant to be used by applications. It is also
14059  * not meant to be used outside the implementation of the
14060  * ClutterActor::allocate virtual function.
14061  *
14062  * Since: 0.8
14063  */
14064 void
14065 clutter_actor_allocate_preferred_size (ClutterActor           *self,
14066                                        ClutterAllocationFlags  flags)
14067 {
14068   gfloat actor_x, actor_y;
14069   gfloat natural_width, natural_height;
14070   ClutterActorBox actor_box;
14071
14072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14073
14074   actor_x = clutter_actor_get_x (self);
14075   actor_y = clutter_actor_get_y (self);
14076
14077   clutter_actor_get_preferred_size (self,
14078                                     NULL, NULL,
14079                                     &natural_width,
14080                                     &natural_height);
14081
14082   actor_box.x1 = actor_x;
14083   actor_box.y1 = actor_y;
14084   actor_box.x2 = actor_box.x1 + natural_width;
14085   actor_box.y2 = actor_box.y1 + natural_height;
14086
14087   clutter_actor_allocate (self, &actor_box, flags);
14088 }
14089
14090 /**
14091  * clutter_actor_allocate_align_fill:
14092  * @self: a #ClutterActor
14093  * @box: a #ClutterActorBox, containing the available width and height
14094  * @x_align: the horizontal alignment, between 0 and 1
14095  * @y_align: the vertical alignment, between 0 and 1
14096  * @x_fill: whether the actor should fill horizontally
14097  * @y_fill: whether the actor should fill vertically
14098  * @flags: allocation flags to be passed to clutter_actor_allocate()
14099  *
14100  * Allocates @self by taking into consideration the available allocation
14101  * area; an alignment factor on either axis; and whether the actor should
14102  * fill the allocation on either axis.
14103  *
14104  * The @box should contain the available allocation width and height;
14105  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14106  * allocation will be offset by their value.
14107  *
14108  * This function takes into consideration the geometry request specified by
14109  * the #ClutterActor:request-mode property, and the text direction.
14110  *
14111  * This function is useful for fluid layout managers, like #ClutterBinLayout
14112  * or #ClutterTableLayout
14113  *
14114  * Since: 1.4
14115  */
14116 void
14117 clutter_actor_allocate_align_fill (ClutterActor           *self,
14118                                    const ClutterActorBox  *box,
14119                                    gdouble                 x_align,
14120                                    gdouble                 y_align,
14121                                    gboolean                x_fill,
14122                                    gboolean                y_fill,
14123                                    ClutterAllocationFlags  flags)
14124 {
14125   ClutterActorPrivate *priv;
14126   ClutterActorBox allocation = { 0, };
14127   gfloat x_offset, y_offset;
14128   gfloat available_width, available_height;
14129   gfloat child_width, child_height;
14130
14131   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14132   g_return_if_fail (box != NULL);
14133   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14134   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14135
14136   priv = self->priv;
14137
14138   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14139   clutter_actor_box_get_size (box, &available_width, &available_height);
14140
14141   if (available_width < 0)
14142     available_width = 0;
14143
14144   if (available_height < 0)
14145     available_height = 0;
14146
14147   if (x_fill)
14148     {
14149       allocation.x1 = x_offset;
14150       allocation.x2 = allocation.x1 + available_width;
14151     }
14152
14153   if (y_fill)
14154     {
14155       allocation.y1 = y_offset;
14156       allocation.y2 = allocation.y1 + available_height;
14157     }
14158
14159   /* if we are filling horizontally and vertically then we're done */
14160   if (x_fill && y_fill)
14161     goto out;
14162
14163   child_width = child_height = 0.0f;
14164
14165   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14166     {
14167       gfloat min_width, natural_width;
14168       gfloat min_height, natural_height;
14169
14170       clutter_actor_get_preferred_width (self, available_height,
14171                                          &min_width,
14172                                          &natural_width);
14173
14174       child_width = CLAMP (natural_width, min_width, available_width);
14175
14176       if (!y_fill)
14177         {
14178           clutter_actor_get_preferred_height (self, child_width,
14179                                               &min_height,
14180                                               &natural_height);
14181
14182           child_height = CLAMP (natural_height, min_height, available_height);
14183         }
14184     }
14185   else
14186     {
14187       gfloat min_width, natural_width;
14188       gfloat min_height, natural_height;
14189
14190       clutter_actor_get_preferred_height (self, available_width,
14191                                           &min_height,
14192                                           &natural_height);
14193
14194       child_height = CLAMP (natural_height, min_height, available_height);
14195
14196       if (!x_fill)
14197         {
14198           clutter_actor_get_preferred_width (self, child_height,
14199                                              &min_width,
14200                                              &natural_width);
14201
14202           child_width = CLAMP (natural_width, min_width, available_width);
14203         }
14204     }
14205
14206   /* invert the horizontal alignment for RTL languages */
14207   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14208     x_align = 1.0 - x_align;
14209
14210   if (!x_fill)
14211     {
14212       allocation.x1 = x_offset
14213                     + ((available_width - child_width) * x_align);
14214       allocation.x2 = allocation.x1 + child_width;
14215     }
14216
14217   if (!y_fill)
14218     {
14219       allocation.y1 = y_offset
14220                     + ((available_height - child_height) * y_align);
14221       allocation.y2 = allocation.y1 + child_height;
14222     }
14223
14224 out:
14225   clutter_actor_box_clamp_to_pixel (&allocation);
14226   clutter_actor_allocate (self, &allocation, flags);
14227 }
14228
14229 /**
14230  * clutter_actor_grab_key_focus:
14231  * @self: a #ClutterActor
14232  *
14233  * Sets the key focus of the #ClutterStage including @self
14234  * to this #ClutterActor.
14235  *
14236  * Since: 1.0
14237  */
14238 void
14239 clutter_actor_grab_key_focus (ClutterActor *self)
14240 {
14241   ClutterActor *stage;
14242
14243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14244
14245   stage = _clutter_actor_get_stage_internal (self);
14246   if (stage != NULL)
14247     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14248 }
14249
14250 /**
14251  * clutter_actor_get_pango_context:
14252  * @self: a #ClutterActor
14253  *
14254  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14255  * is already configured using the appropriate font map, resolution
14256  * and font options.
14257  *
14258  * Unlike clutter_actor_create_pango_context(), this context is owend
14259  * by the #ClutterActor and it will be updated each time the options
14260  * stored by the #ClutterBackend change.
14261  *
14262  * You can use the returned #PangoContext to create a #PangoLayout
14263  * and render text using cogl_pango_render_layout() to reuse the
14264  * glyphs cache also used by Clutter.
14265  *
14266  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14267  *   The returned #PangoContext is owned by the actor and should not be
14268  *   unreferenced by the application code
14269  *
14270  * Since: 1.0
14271  */
14272 PangoContext *
14273 clutter_actor_get_pango_context (ClutterActor *self)
14274 {
14275   ClutterActorPrivate *priv;
14276
14277   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14278
14279   priv = self->priv;
14280
14281   if (priv->pango_context != NULL)
14282     return priv->pango_context;
14283
14284   priv->pango_context = _clutter_context_get_pango_context ();
14285   g_object_ref (priv->pango_context);
14286
14287   return priv->pango_context;
14288 }
14289
14290 /**
14291  * clutter_actor_create_pango_context:
14292  * @self: a #ClutterActor
14293  *
14294  * Creates a #PangoContext for the given actor. The #PangoContext
14295  * is already configured using the appropriate font map, resolution
14296  * and font options.
14297  *
14298  * See also clutter_actor_get_pango_context().
14299  *
14300  * Return value: (transfer full): the newly created #PangoContext.
14301  *   Use g_object_unref() on the returned value to deallocate its
14302  *   resources
14303  *
14304  * Since: 1.0
14305  */
14306 PangoContext *
14307 clutter_actor_create_pango_context (ClutterActor *self)
14308 {
14309   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14310
14311   return _clutter_context_create_pango_context ();
14312 }
14313
14314 /**
14315  * clutter_actor_create_pango_layout:
14316  * @self: a #ClutterActor
14317  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14318  *
14319  * Creates a new #PangoLayout from the same #PangoContext used
14320  * by the #ClutterActor. The #PangoLayout is already configured
14321  * with the font map, resolution and font options, and the
14322  * given @text.
14323  *
14324  * If you want to keep around a #PangoLayout created by this
14325  * function you will have to connect to the #ClutterBackend::font-changed
14326  * and #ClutterBackend::resolution-changed signals, and call
14327  * pango_layout_context_changed() in response to them.
14328  *
14329  * Return value: (transfer full): the newly created #PangoLayout.
14330  *   Use g_object_unref() when done
14331  *
14332  * Since: 1.0
14333  */
14334 PangoLayout *
14335 clutter_actor_create_pango_layout (ClutterActor *self,
14336                                    const gchar  *text)
14337 {
14338   PangoContext *context;
14339   PangoLayout *layout;
14340
14341   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14342
14343   context = clutter_actor_get_pango_context (self);
14344   layout = pango_layout_new (context);
14345
14346   if (text)
14347     pango_layout_set_text (layout, text, -1);
14348
14349   return layout;
14350 }
14351
14352 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14353  * ClutterOffscreenEffect.
14354  */
14355 void
14356 _clutter_actor_set_opacity_override (ClutterActor *self,
14357                                      gint          opacity)
14358 {
14359   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14360
14361   self->priv->opacity_override = opacity;
14362 }
14363
14364 gint
14365 _clutter_actor_get_opacity_override (ClutterActor *self)
14366 {
14367   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14368
14369   return self->priv->opacity_override;
14370 }
14371
14372 /* Allows you to disable applying the actors model view transform during
14373  * a paint. Used by ClutterClone. */
14374 void
14375 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14376                                                 gboolean      enable)
14377 {
14378   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14379
14380   self->priv->enable_model_view_transform = enable;
14381 }
14382
14383 void
14384 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14385                                           gboolean      enable)
14386 {
14387   ClutterActorPrivate *priv;
14388
14389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14390
14391   priv = self->priv;
14392
14393   priv->enable_paint_unmapped = enable;
14394
14395   if (priv->enable_paint_unmapped)
14396     {
14397       /* Make sure that the parents of the widget are realized first;
14398        * otherwise checks in clutter_actor_update_map_state() will
14399        * fail.
14400        */
14401       clutter_actor_realize (self);
14402
14403       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14404     }
14405   else
14406     {
14407       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14408     }
14409 }
14410
14411 static void
14412 clutter_anchor_coord_get_units (ClutterActor      *self,
14413                                 const AnchorCoord *coord,
14414                                 gfloat            *x,
14415                                 gfloat            *y,
14416                                 gfloat            *z)
14417 {
14418   if (coord->is_fractional)
14419     {
14420       gfloat actor_width, actor_height;
14421
14422       clutter_actor_get_size (self, &actor_width, &actor_height);
14423
14424       if (x)
14425         *x = actor_width * coord->v.fraction.x;
14426
14427       if (y)
14428         *y = actor_height * coord->v.fraction.y;
14429
14430       if (z)
14431         *z = 0;
14432     }
14433   else
14434     {
14435       if (x)
14436         *x = coord->v.units.x;
14437
14438       if (y)
14439         *y = coord->v.units.y;
14440
14441       if (z)
14442         *z = coord->v.units.z;
14443     }
14444 }
14445
14446 static void
14447 clutter_anchor_coord_set_units (AnchorCoord *coord,
14448                                 gfloat       x,
14449                                 gfloat       y,
14450                                 gfloat       z)
14451 {
14452   coord->is_fractional = FALSE;
14453   coord->v.units.x = x;
14454   coord->v.units.y = y;
14455   coord->v.units.z = z;
14456 }
14457
14458 static ClutterGravity
14459 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14460 {
14461   if (coord->is_fractional)
14462     {
14463       if (coord->v.fraction.x == 0.0)
14464         {
14465           if (coord->v.fraction.y == 0.0)
14466             return CLUTTER_GRAVITY_NORTH_WEST;
14467           else if (coord->v.fraction.y == 0.5)
14468             return CLUTTER_GRAVITY_WEST;
14469           else if (coord->v.fraction.y == 1.0)
14470             return CLUTTER_GRAVITY_SOUTH_WEST;
14471           else
14472             return CLUTTER_GRAVITY_NONE;
14473         }
14474       else if (coord->v.fraction.x == 0.5)
14475         {
14476           if (coord->v.fraction.y == 0.0)
14477             return CLUTTER_GRAVITY_NORTH;
14478           else if (coord->v.fraction.y == 0.5)
14479             return CLUTTER_GRAVITY_CENTER;
14480           else if (coord->v.fraction.y == 1.0)
14481             return CLUTTER_GRAVITY_SOUTH;
14482           else
14483             return CLUTTER_GRAVITY_NONE;
14484         }
14485       else if (coord->v.fraction.x == 1.0)
14486         {
14487           if (coord->v.fraction.y == 0.0)
14488             return CLUTTER_GRAVITY_NORTH_EAST;
14489           else if (coord->v.fraction.y == 0.5)
14490             return CLUTTER_GRAVITY_EAST;
14491           else if (coord->v.fraction.y == 1.0)
14492             return CLUTTER_GRAVITY_SOUTH_EAST;
14493           else
14494             return CLUTTER_GRAVITY_NONE;
14495         }
14496       else
14497         return CLUTTER_GRAVITY_NONE;
14498     }
14499   else
14500     return CLUTTER_GRAVITY_NONE;
14501 }
14502
14503 static void
14504 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14505                                   ClutterGravity  gravity)
14506 {
14507   switch (gravity)
14508     {
14509     case CLUTTER_GRAVITY_NORTH:
14510       coord->v.fraction.x = 0.5;
14511       coord->v.fraction.y = 0.0;
14512       break;
14513
14514     case CLUTTER_GRAVITY_NORTH_EAST:
14515       coord->v.fraction.x = 1.0;
14516       coord->v.fraction.y = 0.0;
14517       break;
14518
14519     case CLUTTER_GRAVITY_EAST:
14520       coord->v.fraction.x = 1.0;
14521       coord->v.fraction.y = 0.5;
14522       break;
14523
14524     case CLUTTER_GRAVITY_SOUTH_EAST:
14525       coord->v.fraction.x = 1.0;
14526       coord->v.fraction.y = 1.0;
14527       break;
14528
14529     case CLUTTER_GRAVITY_SOUTH:
14530       coord->v.fraction.x = 0.5;
14531       coord->v.fraction.y = 1.0;
14532       break;
14533
14534     case CLUTTER_GRAVITY_SOUTH_WEST:
14535       coord->v.fraction.x = 0.0;
14536       coord->v.fraction.y = 1.0;
14537       break;
14538
14539     case CLUTTER_GRAVITY_WEST:
14540       coord->v.fraction.x = 0.0;
14541       coord->v.fraction.y = 0.5;
14542       break;
14543
14544     case CLUTTER_GRAVITY_NORTH_WEST:
14545       coord->v.fraction.x = 0.0;
14546       coord->v.fraction.y = 0.0;
14547       break;
14548
14549     case CLUTTER_GRAVITY_CENTER:
14550       coord->v.fraction.x = 0.5;
14551       coord->v.fraction.y = 0.5;
14552       break;
14553
14554     default:
14555       coord->v.fraction.x = 0.0;
14556       coord->v.fraction.y = 0.0;
14557       break;
14558     }
14559
14560   coord->is_fractional = TRUE;
14561 }
14562
14563 static gboolean
14564 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14565 {
14566   if (coord->is_fractional)
14567     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14568   else
14569     return (coord->v.units.x == 0.0
14570             && coord->v.units.y == 0.0
14571             && coord->v.units.z == 0.0);
14572 }
14573
14574 /**
14575  * clutter_actor_get_flags:
14576  * @self: a #ClutterActor
14577  *
14578  * Retrieves the flags set on @self
14579  *
14580  * Return value: a bitwise or of #ClutterActorFlags or 0
14581  *
14582  * Since: 1.0
14583  */
14584 ClutterActorFlags
14585 clutter_actor_get_flags (ClutterActor *self)
14586 {
14587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14588
14589   return self->flags;
14590 }
14591
14592 /**
14593  * clutter_actor_set_flags:
14594  * @self: a #ClutterActor
14595  * @flags: the flags to set
14596  *
14597  * Sets @flags on @self
14598  *
14599  * This function will emit notifications for the changed properties
14600  *
14601  * Since: 1.0
14602  */
14603 void
14604 clutter_actor_set_flags (ClutterActor      *self,
14605                          ClutterActorFlags  flags)
14606 {
14607   ClutterActorFlags old_flags;
14608   GObject *obj;
14609   gboolean was_reactive_set, reactive_set;
14610   gboolean was_realized_set, realized_set;
14611   gboolean was_mapped_set, mapped_set;
14612   gboolean was_visible_set, visible_set;
14613
14614   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14615
14616   if (self->flags == flags)
14617     return;
14618
14619   obj = G_OBJECT (self);
14620   g_object_ref (obj);
14621   g_object_freeze_notify (obj);
14622
14623   old_flags = self->flags;
14624
14625   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14626   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14627   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14628   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14629
14630   self->flags |= flags;
14631
14632   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14633   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14634   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14635   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14636
14637   if (reactive_set != was_reactive_set)
14638     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14639
14640   if (realized_set != was_realized_set)
14641     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14642
14643   if (mapped_set != was_mapped_set)
14644     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14645
14646   if (visible_set != was_visible_set)
14647     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14648
14649   g_object_thaw_notify (obj);
14650   g_object_unref (obj);
14651 }
14652
14653 /**
14654  * clutter_actor_unset_flags:
14655  * @self: a #ClutterActor
14656  * @flags: the flags to unset
14657  *
14658  * Unsets @flags on @self
14659  *
14660  * This function will emit notifications for the changed properties
14661  *
14662  * Since: 1.0
14663  */
14664 void
14665 clutter_actor_unset_flags (ClutterActor      *self,
14666                            ClutterActorFlags  flags)
14667 {
14668   ClutterActorFlags old_flags;
14669   GObject *obj;
14670   gboolean was_reactive_set, reactive_set;
14671   gboolean was_realized_set, realized_set;
14672   gboolean was_mapped_set, mapped_set;
14673   gboolean was_visible_set, visible_set;
14674
14675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14676
14677   obj = G_OBJECT (self);
14678   g_object_freeze_notify (obj);
14679
14680   old_flags = self->flags;
14681
14682   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14683   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14684   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14685   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14686
14687   self->flags &= ~flags;
14688
14689   if (self->flags == old_flags)
14690     return;
14691
14692   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14693   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14694   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14695   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14696
14697   if (reactive_set != was_reactive_set)
14698     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14699
14700   if (realized_set != was_realized_set)
14701     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14702
14703   if (mapped_set != was_mapped_set)
14704     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14705
14706   if (visible_set != was_visible_set)
14707     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14708
14709   g_object_thaw_notify (obj);
14710 }
14711
14712 /**
14713  * clutter_actor_get_transformation_matrix:
14714  * @self: a #ClutterActor
14715  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14716  *
14717  * Retrieves the transformations applied to @self relative to its
14718  * parent.
14719  *
14720  * Since: 1.0
14721  */
14722 void
14723 clutter_actor_get_transformation_matrix (ClutterActor *self,
14724                                          CoglMatrix   *matrix)
14725 {
14726   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14727
14728   cogl_matrix_init_identity (matrix);
14729
14730   _clutter_actor_apply_modelview_transform (self, matrix);
14731 }
14732
14733 void
14734 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14735                                    gboolean      is_in_clone_paint)
14736 {
14737   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14738   self->priv->in_clone_paint = is_in_clone_paint;
14739 }
14740
14741 /**
14742  * clutter_actor_is_in_clone_paint:
14743  * @self: a #ClutterActor
14744  *
14745  * Checks whether @self is being currently painted by a #ClutterClone
14746  *
14747  * This function is useful only inside the ::paint virtual function
14748  * implementations or within handlers for the #ClutterActor::paint
14749  * signal
14750  *
14751  * This function should not be used by applications
14752  *
14753  * Return value: %TRUE if the #ClutterActor is currently being painted
14754  *   by a #ClutterClone, and %FALSE otherwise
14755  *
14756  * Since: 1.0
14757  */
14758 gboolean
14759 clutter_actor_is_in_clone_paint (ClutterActor *self)
14760 {
14761   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14762
14763   return self->priv->in_clone_paint;
14764 }
14765
14766 static gboolean
14767 set_direction_recursive (ClutterActor *actor,
14768                          gpointer      user_data)
14769 {
14770   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14771
14772   clutter_actor_set_text_direction (actor, text_dir);
14773
14774   return TRUE;
14775 }
14776
14777 /**
14778  * clutter_actor_set_text_direction:
14779  * @self: a #ClutterActor
14780  * @text_dir: the text direction for @self
14781  *
14782  * Sets the #ClutterTextDirection for an actor
14783  *
14784  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14785  *
14786  * If @self implements #ClutterContainer then this function will recurse
14787  * inside all the children of @self (including the internal ones).
14788  *
14789  * Composite actors not implementing #ClutterContainer, or actors requiring
14790  * special handling when the text direction changes, should connect to
14791  * the #GObject::notify signal for the #ClutterActor:text-direction property
14792  *
14793  * Since: 1.2
14794  */
14795 void
14796 clutter_actor_set_text_direction (ClutterActor         *self,
14797                                   ClutterTextDirection  text_dir)
14798 {
14799   ClutterActorPrivate *priv;
14800
14801   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14802   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14803
14804   priv = self->priv;
14805
14806   if (priv->text_direction != text_dir)
14807     {
14808       priv->text_direction = text_dir;
14809
14810       /* we need to emit the notify::text-direction first, so that
14811        * the sub-classes can catch that and do specific handling of
14812        * the text direction; see clutter_text_direction_changed_cb()
14813        * inside clutter-text.c
14814        */
14815       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14816
14817       _clutter_actor_foreach_child (self, set_direction_recursive,
14818                                     GINT_TO_POINTER (text_dir));
14819
14820       clutter_actor_queue_relayout (self);
14821     }
14822 }
14823
14824 void
14825 _clutter_actor_set_has_pointer (ClutterActor *self,
14826                                 gboolean      has_pointer)
14827 {
14828   ClutterActorPrivate *priv = self->priv;
14829
14830   if (priv->has_pointer != has_pointer)
14831     {
14832       priv->has_pointer = has_pointer;
14833
14834       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14835     }
14836 }
14837
14838 /**
14839  * clutter_actor_get_text_direction:
14840  * @self: a #ClutterActor
14841  *
14842  * Retrieves the value set using clutter_actor_set_text_direction()
14843  *
14844  * If no text direction has been previously set, the default text
14845  * direction, as returned by clutter_get_default_text_direction(), will
14846  * be returned instead
14847  *
14848  * Return value: the #ClutterTextDirection for the actor
14849  *
14850  * Since: 1.2
14851  */
14852 ClutterTextDirection
14853 clutter_actor_get_text_direction (ClutterActor *self)
14854 {
14855   ClutterActorPrivate *priv;
14856
14857   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14858                         CLUTTER_TEXT_DIRECTION_LTR);
14859
14860   priv = self->priv;
14861
14862   /* if no direction has been set yet use the default */
14863   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14864     priv->text_direction = clutter_get_default_text_direction ();
14865
14866   return priv->text_direction;
14867 }
14868
14869 /**
14870  * clutter_actor_push_internal:
14871  * @self: a #ClutterActor
14872  *
14873  * Should be used by actors implementing the #ClutterContainer and with
14874  * internal children added through clutter_actor_set_parent(), for instance:
14875  *
14876  * |[
14877  *   static void
14878  *   my_actor_init (MyActor *self)
14879  *   {
14880  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14881  *
14882  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14883  *
14884  *     /&ast; calling clutter_actor_set_parent() now will result in
14885  *      &ast; the internal flag being set on a child of MyActor
14886  *      &ast;/
14887  *
14888  *     /&ast; internal child - a background texture &ast;/
14889  *     self->priv->background_tex = clutter_texture_new ();
14890  *     clutter_actor_set_parent (self->priv->background_tex,
14891  *                               CLUTTER_ACTOR (self));
14892  *
14893  *     /&ast; internal child - a label &ast;/
14894  *     self->priv->label = clutter_text_new ();
14895  *     clutter_actor_set_parent (self->priv->label,
14896  *                               CLUTTER_ACTOR (self));
14897  *
14898  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14899  *
14900  *     /&ast; calling clutter_actor_set_parent() now will not result in
14901  *      &ast; the internal flag being set on a child of MyActor
14902  *      &ast;/
14903  *   }
14904  * ]|
14905  *
14906  * This function will be used by Clutter to toggle an "internal child"
14907  * flag whenever clutter_actor_set_parent() is called; internal children
14908  * are handled differently by Clutter, specifically when destroying their
14909  * parent.
14910  *
14911  * Call clutter_actor_pop_internal() when you finished adding internal
14912  * children.
14913  *
14914  * Nested calls to clutter_actor_push_internal() are allowed, but each
14915  * one must by followed by a clutter_actor_pop_internal() call.
14916  *
14917  * Since: 1.2
14918  *
14919  * Deprecated: 1.10: All children of an actor are accessible through
14920  *   the #ClutterActor API, and #ClutterActor implements the
14921  *   #ClutterContainer interface, so this function is only useful
14922  *   for legacy containers overriding the default implementation.
14923  */
14924 void
14925 clutter_actor_push_internal (ClutterActor *self)
14926 {
14927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14928
14929   self->priv->internal_child += 1;
14930 }
14931
14932 /**
14933  * clutter_actor_pop_internal:
14934  * @self: a #ClutterActor
14935  *
14936  * Disables the effects of clutter_actor_push_internal().
14937  *
14938  * Since: 1.2
14939  *
14940  * Deprecated: 1.10: All children of an actor are accessible through
14941  *   the #ClutterActor API. This function is only useful for legacy
14942  *   containers overriding the default implementation of the
14943  *   #ClutterContainer interface.
14944  */
14945 void
14946 clutter_actor_pop_internal (ClutterActor *self)
14947 {
14948   ClutterActorPrivate *priv;
14949
14950   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14951
14952   priv = self->priv;
14953
14954   if (priv->internal_child == 0)
14955     {
14956       g_warning ("Mismatched %s: you need to call "
14957                  "clutter_actor_push_composite() at least once before "
14958                  "calling this function", G_STRFUNC);
14959       return;
14960     }
14961
14962   priv->internal_child -= 1;
14963 }
14964
14965 /**
14966  * clutter_actor_has_pointer:
14967  * @self: a #ClutterActor
14968  *
14969  * Checks whether an actor contains the pointer of a
14970  * #ClutterInputDevice
14971  *
14972  * Return value: %TRUE if the actor contains the pointer, and
14973  *   %FALSE otherwise
14974  *
14975  * Since: 1.2
14976  */
14977 gboolean
14978 clutter_actor_has_pointer (ClutterActor *self)
14979 {
14980   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14981
14982   return self->priv->has_pointer;
14983 }
14984
14985 /* XXX: This is a workaround for not being able to break the ABI of
14986  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14987  * clutter_actor_queue_clipped_redraw() for details.
14988  */
14989 ClutterPaintVolume *
14990 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14991 {
14992   return g_object_get_data (G_OBJECT (self),
14993                             "-clutter-actor-queue-redraw-clip");
14994 }
14995
14996 void
14997 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14998                                       ClutterPaintVolume *clip)
14999 {
15000   g_object_set_data (G_OBJECT (self),
15001                      "-clutter-actor-queue-redraw-clip",
15002                      clip);
15003 }
15004
15005 /**
15006  * clutter_actor_has_allocation:
15007  * @self: a #ClutterActor
15008  *
15009  * Checks if the actor has an up-to-date allocation assigned to
15010  * it. This means that the actor should have an allocation: it's
15011  * visible and has a parent. It also means that there is no
15012  * outstanding relayout request in progress for the actor or its
15013  * children (There might be other outstanding layout requests in
15014  * progress that will cause the actor to get a new allocation
15015  * when the stage is laid out, however).
15016  *
15017  * If this function returns %FALSE, then the actor will normally
15018  * be allocated before it is next drawn on the screen.
15019  *
15020  * Return value: %TRUE if the actor has an up-to-date allocation
15021  *
15022  * Since: 1.4
15023  */
15024 gboolean
15025 clutter_actor_has_allocation (ClutterActor *self)
15026 {
15027   ClutterActorPrivate *priv;
15028
15029   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15030
15031   priv = self->priv;
15032
15033   return priv->parent != NULL &&
15034          CLUTTER_ACTOR_IS_VISIBLE (self) &&
15035          !priv->needs_allocation;
15036 }
15037
15038 /**
15039  * clutter_actor_add_action:
15040  * @self: a #ClutterActor
15041  * @action: a #ClutterAction
15042  *
15043  * Adds @action to the list of actions applied to @self
15044  *
15045  * A #ClutterAction can only belong to one actor at a time
15046  *
15047  * The #ClutterActor will hold a reference on @action until either
15048  * clutter_actor_remove_action() or clutter_actor_clear_actions()
15049  * is called
15050  *
15051  * Since: 1.4
15052  */
15053 void
15054 clutter_actor_add_action (ClutterActor  *self,
15055                           ClutterAction *action)
15056 {
15057   ClutterActorPrivate *priv;
15058
15059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15060   g_return_if_fail (CLUTTER_IS_ACTION (action));
15061
15062   priv = self->priv;
15063
15064   if (priv->actions == NULL)
15065     {
15066       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15067       priv->actions->actor = self;
15068     }
15069
15070   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15071
15072   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15073 }
15074
15075 /**
15076  * clutter_actor_add_action_with_name:
15077  * @self: a #ClutterActor
15078  * @name: the name to set on the action
15079  * @action: a #ClutterAction
15080  *
15081  * A convenience function for setting the name of a #ClutterAction
15082  * while adding it to the list of actions applied to @self
15083  *
15084  * This function is the logical equivalent of:
15085  *
15086  * |[
15087  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15088  *   clutter_actor_add_action (self, action);
15089  * ]|
15090  *
15091  * Since: 1.4
15092  */
15093 void
15094 clutter_actor_add_action_with_name (ClutterActor  *self,
15095                                     const gchar   *name,
15096                                     ClutterAction *action)
15097 {
15098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15099   g_return_if_fail (name != NULL);
15100   g_return_if_fail (CLUTTER_IS_ACTION (action));
15101
15102   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15103   clutter_actor_add_action (self, action);
15104 }
15105
15106 /**
15107  * clutter_actor_remove_action:
15108  * @self: a #ClutterActor
15109  * @action: a #ClutterAction
15110  *
15111  * Removes @action from the list of actions applied to @self
15112  *
15113  * The reference held by @self on the #ClutterAction will be released
15114  *
15115  * Since: 1.4
15116  */
15117 void
15118 clutter_actor_remove_action (ClutterActor  *self,
15119                              ClutterAction *action)
15120 {
15121   ClutterActorPrivate *priv;
15122
15123   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15124   g_return_if_fail (CLUTTER_IS_ACTION (action));
15125
15126   priv = self->priv;
15127
15128   if (priv->actions == NULL)
15129     return;
15130
15131   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15132
15133   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15134     g_clear_object (&priv->actions);
15135
15136   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15137 }
15138
15139 /**
15140  * clutter_actor_remove_action_by_name:
15141  * @self: a #ClutterActor
15142  * @name: the name of the action to remove
15143  *
15144  * Removes the #ClutterAction with the given name from the list
15145  * of actions applied to @self
15146  *
15147  * Since: 1.4
15148  */
15149 void
15150 clutter_actor_remove_action_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->actions == NULL)
15162     return;
15163
15164   meta = _clutter_meta_group_get_meta (priv->actions, name);
15165   if (meta == NULL)
15166     return;
15167
15168   _clutter_meta_group_remove_meta (priv->actions, meta);
15169
15170   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15171 }
15172
15173 /**
15174  * clutter_actor_get_actions:
15175  * @self: a #ClutterActor
15176  *
15177  * Retrieves the list of actions applied to @self
15178  *
15179  * Return value: (transfer container) (element-type Clutter.Action): a copy
15180  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
15181  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15182  *   allocated by the returned #GList
15183  *
15184  * Since: 1.4
15185  */
15186 GList *
15187 clutter_actor_get_actions (ClutterActor *self)
15188 {
15189   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15190
15191   if (self->priv->actions == NULL)
15192     return NULL;
15193
15194   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15195 }
15196
15197 /**
15198  * clutter_actor_get_action:
15199  * @self: a #ClutterActor
15200  * @name: the name of the action to retrieve
15201  *
15202  * Retrieves the #ClutterAction with the given name in the list
15203  * of actions applied to @self
15204  *
15205  * Return value: (transfer none): a #ClutterAction for the given
15206  *   name, or %NULL. The returned #ClutterAction is owned by the
15207  *   actor and it should not be unreferenced directly
15208  *
15209  * Since: 1.4
15210  */
15211 ClutterAction *
15212 clutter_actor_get_action (ClutterActor *self,
15213                           const gchar  *name)
15214 {
15215   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15216   g_return_val_if_fail (name != NULL, NULL);
15217
15218   if (self->priv->actions == NULL)
15219     return NULL;
15220
15221   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15222 }
15223
15224 /**
15225  * clutter_actor_clear_actions:
15226  * @self: a #ClutterActor
15227  *
15228  * Clears the list of actions applied to @self
15229  *
15230  * Since: 1.4
15231  */
15232 void
15233 clutter_actor_clear_actions (ClutterActor *self)
15234 {
15235   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15236
15237   if (self->priv->actions == NULL)
15238     return;
15239
15240   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15241 }
15242
15243 /**
15244  * clutter_actor_add_constraint:
15245  * @self: a #ClutterActor
15246  * @constraint: a #ClutterConstraint
15247  *
15248  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15249  * to @self
15250  *
15251  * The #ClutterActor will hold a reference on the @constraint until
15252  * either clutter_actor_remove_constraint() or
15253  * clutter_actor_clear_constraints() is called.
15254  *
15255  * Since: 1.4
15256  */
15257 void
15258 clutter_actor_add_constraint (ClutterActor      *self,
15259                               ClutterConstraint *constraint)
15260 {
15261   ClutterActorPrivate *priv;
15262
15263   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15264   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15265
15266   priv = self->priv;
15267
15268   if (priv->constraints == NULL)
15269     {
15270       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15271       priv->constraints->actor = self;
15272     }
15273
15274   _clutter_meta_group_add_meta (priv->constraints,
15275                                 CLUTTER_ACTOR_META (constraint));
15276   clutter_actor_queue_relayout (self);
15277
15278   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15279 }
15280
15281 /**
15282  * clutter_actor_add_constraint_with_name:
15283  * @self: a #ClutterActor
15284  * @name: the name to set on the constraint
15285  * @constraint: a #ClutterConstraint
15286  *
15287  * A convenience function for setting the name of a #ClutterConstraint
15288  * while adding it to the list of constraints applied to @self
15289  *
15290  * This function is the logical equivalent of:
15291  *
15292  * |[
15293  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15294  *   clutter_actor_add_constraint (self, constraint);
15295  * ]|
15296  *
15297  * Since: 1.4
15298  */
15299 void
15300 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15301                                         const gchar       *name,
15302                                         ClutterConstraint *constraint)
15303 {
15304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15305   g_return_if_fail (name != NULL);
15306   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15307
15308   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15309   clutter_actor_add_constraint (self, constraint);
15310 }
15311
15312 /**
15313  * clutter_actor_remove_constraint:
15314  * @self: a #ClutterActor
15315  * @constraint: a #ClutterConstraint
15316  *
15317  * Removes @constraint from the list of constraints applied to @self
15318  *
15319  * The reference held by @self on the #ClutterConstraint will be released
15320  *
15321  * Since: 1.4
15322  */
15323 void
15324 clutter_actor_remove_constraint (ClutterActor      *self,
15325                                  ClutterConstraint *constraint)
15326 {
15327   ClutterActorPrivate *priv;
15328
15329   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15330   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15331
15332   priv = self->priv;
15333
15334   if (priv->constraints == NULL)
15335     return;
15336
15337   _clutter_meta_group_remove_meta (priv->constraints,
15338                                    CLUTTER_ACTOR_META (constraint));
15339
15340   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15341     g_clear_object (&priv->constraints);
15342
15343   clutter_actor_queue_relayout (self);
15344
15345   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15346 }
15347
15348 /**
15349  * clutter_actor_remove_constraint_by_name:
15350  * @self: a #ClutterActor
15351  * @name: the name of the constraint to remove
15352  *
15353  * Removes the #ClutterConstraint with the given name from the list
15354  * of constraints applied to @self
15355  *
15356  * Since: 1.4
15357  */
15358 void
15359 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15360                                          const gchar  *name)
15361 {
15362   ClutterActorPrivate *priv;
15363   ClutterActorMeta *meta;
15364
15365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15366   g_return_if_fail (name != NULL);
15367
15368   priv = self->priv;
15369
15370   if (priv->constraints == NULL)
15371     return;
15372
15373   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15374   if (meta == NULL)
15375     return;
15376
15377   _clutter_meta_group_remove_meta (priv->constraints, meta);
15378   clutter_actor_queue_relayout (self);
15379 }
15380
15381 /**
15382  * clutter_actor_get_constraints:
15383  * @self: a #ClutterActor
15384  *
15385  * Retrieves the list of constraints applied to @self
15386  *
15387  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15388  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15389  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15390  *   allocated by the returned #GList
15391  *
15392  * Since: 1.4
15393  */
15394 GList *
15395 clutter_actor_get_constraints (ClutterActor *self)
15396 {
15397   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15398
15399   if (self->priv->constraints == NULL)
15400     return NULL;
15401
15402   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15403 }
15404
15405 /**
15406  * clutter_actor_get_constraint:
15407  * @self: a #ClutterActor
15408  * @name: the name of the constraint to retrieve
15409  *
15410  * Retrieves the #ClutterConstraint with the given name in the list
15411  * of constraints applied to @self
15412  *
15413  * Return value: (transfer none): a #ClutterConstraint for the given
15414  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15415  *   actor and it should not be unreferenced directly
15416  *
15417  * Since: 1.4
15418  */
15419 ClutterConstraint *
15420 clutter_actor_get_constraint (ClutterActor *self,
15421                               const gchar  *name)
15422 {
15423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15424   g_return_val_if_fail (name != NULL, NULL);
15425
15426   if (self->priv->constraints == NULL)
15427     return NULL;
15428
15429   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15430 }
15431
15432 /**
15433  * clutter_actor_clear_constraints:
15434  * @self: a #ClutterActor
15435  *
15436  * Clears the list of constraints applied to @self
15437  *
15438  * Since: 1.4
15439  */
15440 void
15441 clutter_actor_clear_constraints (ClutterActor *self)
15442 {
15443   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15444
15445   if (self->priv->constraints == NULL)
15446     return;
15447
15448   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15449
15450   clutter_actor_queue_relayout (self);
15451 }
15452
15453 /**
15454  * clutter_actor_set_clip_to_allocation:
15455  * @self: a #ClutterActor
15456  * @clip_set: %TRUE to apply a clip tracking the allocation
15457  *
15458  * Sets whether @self should be clipped to the same size as its
15459  * allocation
15460  *
15461  * Since: 1.4
15462  */
15463 void
15464 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15465                                       gboolean      clip_set)
15466 {
15467   ClutterActorPrivate *priv;
15468
15469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15470
15471   clip_set = !!clip_set;
15472
15473   priv = self->priv;
15474
15475   if (priv->clip_to_allocation != clip_set)
15476     {
15477       priv->clip_to_allocation = clip_set;
15478
15479       clutter_actor_queue_redraw (self);
15480
15481       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15482     }
15483 }
15484
15485 /**
15486  * clutter_actor_get_clip_to_allocation:
15487  * @self: a #ClutterActor
15488  *
15489  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15490  *
15491  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15492  *
15493  * Since: 1.4
15494  */
15495 gboolean
15496 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15497 {
15498   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15499
15500   return self->priv->clip_to_allocation;
15501 }
15502
15503 /**
15504  * clutter_actor_add_effect:
15505  * @self: a #ClutterActor
15506  * @effect: a #ClutterEffect
15507  *
15508  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15509  *
15510  * The #ClutterActor will hold a reference on the @effect until either
15511  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15512  * called.
15513  *
15514  * Since: 1.4
15515  */
15516 void
15517 clutter_actor_add_effect (ClutterActor  *self,
15518                           ClutterEffect *effect)
15519 {
15520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15521   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15522
15523   _clutter_actor_add_effect_internal (self, effect);
15524
15525   clutter_actor_queue_redraw (self);
15526
15527   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15528 }
15529
15530 /**
15531  * clutter_actor_add_effect_with_name:
15532  * @self: a #ClutterActor
15533  * @name: the name to set on the effect
15534  * @effect: a #ClutterEffect
15535  *
15536  * A convenience function for setting the name of a #ClutterEffect
15537  * while adding it to the list of effectss applied to @self
15538  *
15539  * This function is the logical equivalent of:
15540  *
15541  * |[
15542  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15543  *   clutter_actor_add_effect (self, effect);
15544  * ]|
15545  *
15546  * Since: 1.4
15547  */
15548 void
15549 clutter_actor_add_effect_with_name (ClutterActor  *self,
15550                                     const gchar   *name,
15551                                     ClutterEffect *effect)
15552 {
15553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15554   g_return_if_fail (name != NULL);
15555   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15556
15557   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15558   clutter_actor_add_effect (self, effect);
15559 }
15560
15561 /**
15562  * clutter_actor_remove_effect:
15563  * @self: a #ClutterActor
15564  * @effect: a #ClutterEffect
15565  *
15566  * Removes @effect from the list of effects applied to @self
15567  *
15568  * The reference held by @self on the #ClutterEffect will be released
15569  *
15570  * Since: 1.4
15571  */
15572 void
15573 clutter_actor_remove_effect (ClutterActor  *self,
15574                              ClutterEffect *effect)
15575 {
15576   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15577   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15578
15579   _clutter_actor_remove_effect_internal (self, effect);
15580
15581   clutter_actor_queue_redraw (self);
15582
15583   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15584 }
15585
15586 /**
15587  * clutter_actor_remove_effect_by_name:
15588  * @self: a #ClutterActor
15589  * @name: the name of the effect to remove
15590  *
15591  * Removes the #ClutterEffect with the given name from the list
15592  * of effects applied to @self
15593  *
15594  * Since: 1.4
15595  */
15596 void
15597 clutter_actor_remove_effect_by_name (ClutterActor *self,
15598                                      const gchar  *name)
15599 {
15600   ClutterActorPrivate *priv;
15601   ClutterActorMeta *meta;
15602
15603   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15604   g_return_if_fail (name != NULL);
15605
15606   priv = self->priv;
15607
15608   if (priv->effects == NULL)
15609     return;
15610
15611   meta = _clutter_meta_group_get_meta (priv->effects, name);
15612   if (meta == NULL)
15613     return;
15614
15615   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15616 }
15617
15618 /**
15619  * clutter_actor_get_effects:
15620  * @self: a #ClutterActor
15621  *
15622  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15623  *
15624  * Return value: (transfer container) (element-type Clutter.Effect): a list
15625  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15626  *   list are owned by Clutter and they should not be freed. You should
15627  *   free the returned list using g_list_free() when done
15628  *
15629  * Since: 1.4
15630  */
15631 GList *
15632 clutter_actor_get_effects (ClutterActor *self)
15633 {
15634   ClutterActorPrivate *priv;
15635
15636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15637
15638   priv = self->priv;
15639
15640   if (priv->effects == NULL)
15641     return NULL;
15642
15643   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15644 }
15645
15646 /**
15647  * clutter_actor_get_effect:
15648  * @self: a #ClutterActor
15649  * @name: the name of the effect to retrieve
15650  *
15651  * Retrieves the #ClutterEffect with the given name in the list
15652  * of effects applied to @self
15653  *
15654  * Return value: (transfer none): a #ClutterEffect for the given
15655  *   name, or %NULL. The returned #ClutterEffect is owned by the
15656  *   actor and it should not be unreferenced directly
15657  *
15658  * Since: 1.4
15659  */
15660 ClutterEffect *
15661 clutter_actor_get_effect (ClutterActor *self,
15662                           const gchar  *name)
15663 {
15664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15665   g_return_val_if_fail (name != NULL, NULL);
15666
15667   if (self->priv->effects == NULL)
15668     return NULL;
15669
15670   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15671 }
15672
15673 /**
15674  * clutter_actor_clear_effects:
15675  * @self: a #ClutterActor
15676  *
15677  * Clears the list of effects applied to @self
15678  *
15679  * Since: 1.4
15680  */
15681 void
15682 clutter_actor_clear_effects (ClutterActor *self)
15683 {
15684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15685
15686   if (self->priv->effects == NULL)
15687     return;
15688
15689   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15690
15691   clutter_actor_queue_redraw (self);
15692 }
15693
15694 /**
15695  * clutter_actor_has_key_focus:
15696  * @self: a #ClutterActor
15697  *
15698  * Checks whether @self is the #ClutterActor that has key focus
15699  *
15700  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15701  *
15702  * Since: 1.4
15703  */
15704 gboolean
15705 clutter_actor_has_key_focus (ClutterActor *self)
15706 {
15707   ClutterActor *stage;
15708
15709   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15710
15711   stage = _clutter_actor_get_stage_internal (self);
15712   if (stage == NULL)
15713     return FALSE;
15714
15715   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15716 }
15717
15718 static gboolean
15719 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15720                                       ClutterPaintVolume *pv)
15721 {
15722   ClutterActorPrivate *priv = self->priv;
15723
15724   /* Actors are only expected to report a valid paint volume
15725    * while they have a valid allocation. */
15726   if (G_UNLIKELY (priv->needs_allocation))
15727     {
15728       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15729                     "Actor needs allocation",
15730                     _clutter_actor_get_debug_name (self));
15731       return FALSE;
15732     }
15733
15734   /* Check if there are any handlers connected to the paint
15735    * signal. If there are then all bets are off for what the paint
15736    * volume for this actor might possibly be!
15737    *
15738    * XXX: It's expected that this is going to end up being quite a
15739    * costly check to have to do here, but we haven't come up with
15740    * another solution that can reliably catch paint signal handlers at
15741    * the right time to either avoid artefacts due to invalid stage
15742    * clipping or due to incorrect culling.
15743    *
15744    * Previously we checked in clutter_actor_paint(), but at that time
15745    * we may already be using a stage clip that could be derived from
15746    * an invalid paint-volume. We used to try and handle that by
15747    * queuing a follow up, unclipped, redraw but still the previous
15748    * checking wasn't enough to catch invalid volumes involved in
15749    * culling (considering that containers may derive their volume from
15750    * children that haven't yet been painted)
15751    *
15752    * Longer term, improved solutions could be:
15753    * - Disallow painting in the paint signal, only allow using it
15754    *   for tracking when paints happen. We can add another API that
15755    *   allows monkey patching the paint of arbitrary actors but in a
15756    *   more controlled way and that also supports modifying the
15757    *   paint-volume.
15758    * - If we could be notified somehow when signal handlers are
15759    *   connected we wouldn't have to poll for handlers like this.
15760    */
15761   if (g_signal_has_handler_pending (self,
15762                                     actor_signals[PAINT],
15763                                     0,
15764                                     TRUE))
15765     {
15766       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15767                     "Actor has \"paint\" signal handlers",
15768                     _clutter_actor_get_debug_name (self));
15769       return FALSE;
15770     }
15771
15772   _clutter_paint_volume_init_static (pv, self);
15773
15774   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15775     {
15776       clutter_paint_volume_free (pv);
15777       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15778                     "Actor failed to report a volume",
15779                     _clutter_actor_get_debug_name (self));
15780       return FALSE;
15781     }
15782
15783   /* since effects can modify the paint volume, we allow them to actually
15784    * do this by making get_paint_volume() "context sensitive"
15785    */
15786   if (priv->effects != NULL)
15787     {
15788       if (priv->current_effect != NULL)
15789         {
15790           const GList *effects, *l;
15791
15792           /* if we are being called from within the paint sequence of
15793            * an actor, get the paint volume up to the current effect
15794            */
15795           effects = _clutter_meta_group_peek_metas (priv->effects);
15796           for (l = effects;
15797                l != NULL || (l != NULL && l->data != priv->current_effect);
15798                l = l->next)
15799             {
15800               if (!_clutter_effect_get_paint_volume (l->data, pv))
15801                 {
15802                   clutter_paint_volume_free (pv);
15803                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15804                                 "Effect (%s) failed to report a volume",
15805                                 _clutter_actor_get_debug_name (self),
15806                                 _clutter_actor_meta_get_debug_name (l->data));
15807                   return FALSE;
15808                 }
15809             }
15810         }
15811       else
15812         {
15813           const GList *effects, *l;
15814
15815           /* otherwise, get the cumulative volume */
15816           effects = _clutter_meta_group_peek_metas (priv->effects);
15817           for (l = effects; l != NULL; l = l->next)
15818             if (!_clutter_effect_get_paint_volume (l->data, pv))
15819               {
15820                 clutter_paint_volume_free (pv);
15821                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15822                               "Effect (%s) failed to report a volume",
15823                               _clutter_actor_get_debug_name (self),
15824                               _clutter_actor_meta_get_debug_name (l->data));
15825                 return FALSE;
15826               }
15827         }
15828     }
15829
15830   return TRUE;
15831 }
15832
15833 /* The public clutter_actor_get_paint_volume API returns a const
15834  * pointer since we return a pointer directly to the cached
15835  * PaintVolume associated with the actor and don't want the user to
15836  * inadvertently modify it, but for internal uses we sometimes need
15837  * access to the same PaintVolume but need to apply some book-keeping
15838  * modifications to it so we don't want a const pointer.
15839  */
15840 static ClutterPaintVolume *
15841 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15842 {
15843   ClutterActorPrivate *priv;
15844
15845   priv = self->priv;
15846
15847   if (priv->paint_volume_valid)
15848     clutter_paint_volume_free (&priv->paint_volume);
15849
15850   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15851     {
15852       priv->paint_volume_valid = TRUE;
15853       return &priv->paint_volume;
15854     }
15855   else
15856     {
15857       priv->paint_volume_valid = FALSE;
15858       return NULL;
15859     }
15860 }
15861
15862 /**
15863  * clutter_actor_get_paint_volume:
15864  * @self: a #ClutterActor
15865  *
15866  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15867  * when a paint volume can't be determined.
15868  *
15869  * The paint volume is defined as the 3D space occupied by an actor
15870  * when being painted.
15871  *
15872  * This function will call the <function>get_paint_volume()</function>
15873  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15874  * should not usually care about overriding the default implementation,
15875  * unless they are, for instance: painting outside their allocation, or
15876  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15877  * 3D depth).
15878  *
15879  * <note>2D actors overriding <function>get_paint_volume()</function>
15880  * ensure their volume has a depth of 0. (This will be true so long as
15881  * you don't call clutter_paint_volume_set_depth().)</note>
15882  *
15883  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15884  *   or %NULL if no volume could be determined. The returned pointer
15885  *   is not guaranteed to be valid across multiple frames; if you want
15886  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15887  *
15888  * Since: 1.6
15889  */
15890 const ClutterPaintVolume *
15891 clutter_actor_get_paint_volume (ClutterActor *self)
15892 {
15893   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15894
15895   return _clutter_actor_get_paint_volume_mutable (self);
15896 }
15897
15898 /**
15899  * clutter_actor_get_transformed_paint_volume:
15900  * @self: a #ClutterActor
15901  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15902  *    (or %NULL for the stage)
15903  *
15904  * Retrieves the 3D paint volume of an actor like
15905  * clutter_actor_get_paint_volume() does (Please refer to the
15906  * documentation of clutter_actor_get_paint_volume() for more
15907  * details.) and it additionally transforms the paint volume into the
15908  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15909  * is passed for @relative_to_ancestor)
15910  *
15911  * This can be used by containers that base their paint volume on
15912  * the volume of their children. Such containers can query the
15913  * transformed paint volume of all of its children and union them
15914  * together using clutter_paint_volume_union().
15915  *
15916  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15917  *   or %NULL if no volume could be determined. The returned pointer is
15918  *   not guaranteed to be valid across multiple frames; if you wish to
15919  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15920  *
15921  * Since: 1.6
15922  */
15923 const ClutterPaintVolume *
15924 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15925                                             ClutterActor *relative_to_ancestor)
15926 {
15927   const ClutterPaintVolume *volume;
15928   ClutterActor *stage;
15929   ClutterPaintVolume *transformed_volume;
15930
15931   stage = _clutter_actor_get_stage_internal (self);
15932   if (G_UNLIKELY (stage == NULL))
15933     return NULL;
15934
15935   if (relative_to_ancestor == NULL)
15936     relative_to_ancestor = stage;
15937
15938   volume = clutter_actor_get_paint_volume (self);
15939   if (volume == NULL)
15940     return NULL;
15941
15942   transformed_volume =
15943     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15944
15945   _clutter_paint_volume_copy_static (volume, transformed_volume);
15946
15947   _clutter_paint_volume_transform_relative (transformed_volume,
15948                                             relative_to_ancestor);
15949
15950   return transformed_volume;
15951 }
15952
15953 /**
15954  * clutter_actor_get_paint_box:
15955  * @self: a #ClutterActor
15956  * @box: (out): return location for a #ClutterActorBox
15957  *
15958  * Retrieves the paint volume of the passed #ClutterActor, and
15959  * transforms it into a 2D bounding box in stage coordinates.
15960  *
15961  * This function is useful to determine the on screen area occupied by
15962  * the actor. The box is only an approximation and may often be
15963  * considerably larger due to the optimizations used to calculate the
15964  * box. The box is never smaller though, so it can reliably be used
15965  * for culling.
15966  *
15967  * There are times when a 2D paint box can't be determined, e.g.
15968  * because the actor isn't yet parented under a stage or because
15969  * the actor is unable to determine a paint volume.
15970  *
15971  * Return value: %TRUE if a 2D paint box could be determined, else
15972  * %FALSE.
15973  *
15974  * Since: 1.6
15975  */
15976 gboolean
15977 clutter_actor_get_paint_box (ClutterActor    *self,
15978                              ClutterActorBox *box)
15979 {
15980   ClutterActor *stage;
15981   ClutterPaintVolume *pv;
15982
15983   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15984   g_return_val_if_fail (box != NULL, FALSE);
15985
15986   stage = _clutter_actor_get_stage_internal (self);
15987   if (G_UNLIKELY (!stage))
15988     return FALSE;
15989
15990   pv = _clutter_actor_get_paint_volume_mutable (self);
15991   if (G_UNLIKELY (!pv))
15992     return FALSE;
15993
15994   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15995
15996   return TRUE;
15997 }
15998
15999 /**
16000  * clutter_actor_has_overlaps:
16001  * @self: A #ClutterActor
16002  *
16003  * Asks the actor's implementation whether it may contain overlapping
16004  * primitives.
16005  *
16006  * For example; Clutter may use this to determine whether the painting
16007  * should be redirected to an offscreen buffer to correctly implement
16008  * the opacity property.
16009  *
16010  * Custom actors can override the default response by implementing the
16011  * #ClutterActor <function>has_overlaps</function> virtual function. See
16012  * clutter_actor_set_offscreen_redirect() for more information.
16013  *
16014  * Return value: %TRUE if the actor may have overlapping primitives, and
16015  *   %FALSE otherwise
16016  *
16017  * Since: 1.8
16018  */
16019 gboolean
16020 clutter_actor_has_overlaps (ClutterActor *self)
16021 {
16022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
16023
16024   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
16025 }
16026
16027 /**
16028  * clutter_actor_has_effects:
16029  * @self: A #ClutterActor
16030  *
16031  * Returns whether the actor has any effects applied.
16032  *
16033  * Return value: %TRUE if the actor has any effects,
16034  *   %FALSE otherwise
16035  *
16036  * Since: 1.10
16037  */
16038 gboolean
16039 clutter_actor_has_effects (ClutterActor *self)
16040 {
16041   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16042
16043   if (self->priv->effects == NULL)
16044     return FALSE;
16045
16046   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16047 }
16048
16049 /**
16050  * clutter_actor_has_constraints:
16051  * @self: A #ClutterActor
16052  *
16053  * Returns whether the actor has any constraints applied.
16054  *
16055  * Return value: %TRUE if the actor has any constraints,
16056  *   %FALSE otherwise
16057  *
16058  * Since: 1.10
16059  */
16060 gboolean
16061 clutter_actor_has_constraints (ClutterActor *self)
16062 {
16063   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16064
16065   return self->priv->constraints != NULL;
16066 }
16067
16068 /**
16069  * clutter_actor_has_actions:
16070  * @self: A #ClutterActor
16071  *
16072  * Returns whether the actor has any actions applied.
16073  *
16074  * Return value: %TRUE if the actor has any actions,
16075  *   %FALSE otherwise
16076  *
16077  * Since: 1.10
16078  */
16079 gboolean
16080 clutter_actor_has_actions (ClutterActor *self)
16081 {
16082   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16083
16084   return self->priv->actions != NULL;
16085 }
16086
16087 /**
16088  * clutter_actor_get_n_children:
16089  * @self: a #ClutterActor
16090  *
16091  * Retrieves the number of children of @self.
16092  *
16093  * Return value: the number of children of an actor
16094  *
16095  * Since: 1.10
16096  */
16097 gint
16098 clutter_actor_get_n_children (ClutterActor *self)
16099 {
16100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16101
16102   return self->priv->n_children;
16103 }
16104
16105 /**
16106  * clutter_actor_get_child_at_index:
16107  * @self: a #ClutterActor
16108  * @index_: the position in the list of children
16109  *
16110  * Retrieves the actor at the given @index_ inside the list of
16111  * children of @self.
16112  *
16113  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16114  *
16115  * Since: 1.10
16116  */
16117 ClutterActor *
16118 clutter_actor_get_child_at_index (ClutterActor *self,
16119                                   gint          index_)
16120 {
16121   ClutterActor *iter;
16122   int i;
16123
16124   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16125   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16126
16127   for (iter = self->priv->first_child, i = 0;
16128        iter != NULL && i < index_;
16129        iter = iter->priv->next_sibling, i += 1)
16130     ;
16131
16132   return iter;
16133 }
16134
16135 /*< private >
16136  * _clutter_actor_foreach_child:
16137  * @actor: The actor whos children you want to iterate
16138  * @callback: The function to call for each child
16139  * @user_data: Private data to pass to @callback
16140  *
16141  * Calls a given @callback once for each child of the specified @actor and
16142  * passing the @user_data pointer each time.
16143  *
16144  * Return value: returns %TRUE if all children were iterated, else
16145  *    %FALSE if a callback broke out of iteration early.
16146  */
16147 gboolean
16148 _clutter_actor_foreach_child (ClutterActor           *self,
16149                               ClutterForeachCallback  callback,
16150                               gpointer                user_data)
16151 {
16152   ClutterActor *iter;
16153   gboolean cont;
16154
16155   if (self->priv->first_child == NULL)
16156     return TRUE;
16157
16158   cont = TRUE;
16159   iter = self->priv->first_child;
16160
16161   /* we use this form so that it's safe to change the children
16162    * list while iterating it
16163    */
16164   while (cont && iter != NULL)
16165     {
16166       ClutterActor *next = iter->priv->next_sibling;
16167
16168       cont = callback (iter, user_data);
16169
16170       iter = next;
16171     }
16172
16173   return cont;
16174 }
16175
16176 #if 0
16177 /* For debugging purposes this gives us a simple way to print out
16178  * the scenegraph e.g in gdb using:
16179  * [|
16180  *   _clutter_actor_traverse (stage,
16181  *                            0,
16182  *                            clutter_debug_print_actor_cb,
16183  *                            NULL,
16184  *                            NULL);
16185  * |]
16186  */
16187 static ClutterActorTraverseVisitFlags
16188 clutter_debug_print_actor_cb (ClutterActor *actor,
16189                               int depth,
16190                               void *user_data)
16191 {
16192   g_print ("%*s%s:%p\n",
16193            depth * 2, "",
16194            _clutter_actor_get_debug_name (actor),
16195            actor);
16196
16197   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16198 }
16199 #endif
16200
16201 static void
16202 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16203                                  ClutterTraverseCallback callback,
16204                                  gpointer                user_data)
16205 {
16206   GQueue *queue = g_queue_new ();
16207   ClutterActor dummy;
16208   int current_depth = 0;
16209
16210   g_queue_push_tail (queue, actor);
16211   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16212
16213   while ((actor = g_queue_pop_head (queue)))
16214     {
16215       ClutterActorTraverseVisitFlags flags;
16216
16217       if (actor == &dummy)
16218         {
16219           current_depth++;
16220           g_queue_push_tail (queue, &dummy);
16221           continue;
16222         }
16223
16224       flags = callback (actor, current_depth, user_data);
16225       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16226         break;
16227       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16228         {
16229           ClutterActor *iter;
16230
16231           for (iter = actor->priv->first_child;
16232                iter != NULL;
16233                iter = iter->priv->next_sibling)
16234             {
16235               g_queue_push_tail (queue, iter);
16236             }
16237         }
16238     }
16239
16240   g_queue_free (queue);
16241 }
16242
16243 static ClutterActorTraverseVisitFlags
16244 _clutter_actor_traverse_depth (ClutterActor           *actor,
16245                                ClutterTraverseCallback before_children_callback,
16246                                ClutterTraverseCallback after_children_callback,
16247                                int                     current_depth,
16248                                gpointer                user_data)
16249 {
16250   ClutterActorTraverseVisitFlags flags;
16251
16252   flags = before_children_callback (actor, current_depth, user_data);
16253   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16254     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16255
16256   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16257     {
16258       ClutterActor *iter;
16259
16260       for (iter = actor->priv->first_child;
16261            iter != NULL;
16262            iter = iter->priv->next_sibling)
16263         {
16264           flags = _clutter_actor_traverse_depth (iter,
16265                                                  before_children_callback,
16266                                                  after_children_callback,
16267                                                  current_depth + 1,
16268                                                  user_data);
16269
16270           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16271             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16272         }
16273     }
16274
16275   if (after_children_callback)
16276     return after_children_callback (actor, current_depth, user_data);
16277   else
16278     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16279 }
16280
16281 /* _clutter_actor_traverse:
16282  * @actor: The actor to start traversing the graph from
16283  * @flags: These flags may affect how the traversal is done
16284  * @before_children_callback: A function to call before visiting the
16285  *   children of the current actor.
16286  * @after_children_callback: A function to call after visiting the
16287  *   children of the current actor. (Ignored if
16288  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16289  * @user_data: The private data to pass to the callbacks
16290  *
16291  * Traverses the scenegraph starting at the specified @actor and
16292  * descending through all its children and its children's children.
16293  * For each actor traversed @before_children_callback and
16294  * @after_children_callback are called with the specified
16295  * @user_data, before and after visiting that actor's children.
16296  *
16297  * The callbacks can return flags that affect the ongoing traversal
16298  * such as by skipping over an actors children or bailing out of
16299  * any further traversing.
16300  */
16301 void
16302 _clutter_actor_traverse (ClutterActor              *actor,
16303                          ClutterActorTraverseFlags  flags,
16304                          ClutterTraverseCallback    before_children_callback,
16305                          ClutterTraverseCallback    after_children_callback,
16306                          gpointer                   user_data)
16307 {
16308   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16309     _clutter_actor_traverse_breadth (actor,
16310                                      before_children_callback,
16311                                      user_data);
16312   else /* DEPTH_FIRST */
16313     _clutter_actor_traverse_depth (actor,
16314                                    before_children_callback,
16315                                    after_children_callback,
16316                                    0, /* start depth */
16317                                    user_data);
16318 }
16319
16320 static void
16321 on_layout_manager_changed (ClutterLayoutManager *manager,
16322                            ClutterActor         *self)
16323 {
16324   clutter_actor_queue_relayout (self);
16325 }
16326
16327 /**
16328  * clutter_actor_set_layout_manager:
16329  * @self: a #ClutterActor
16330  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16331  *
16332  * Sets the #ClutterLayoutManager delegate object that will be used to
16333  * lay out the children of @self.
16334  *
16335  * The #ClutterActor will take a reference on the passed @manager which
16336  * will be released either when the layout manager is removed, or when
16337  * the actor is destroyed.
16338  *
16339  * Since: 1.10
16340  */
16341 void
16342 clutter_actor_set_layout_manager (ClutterActor         *self,
16343                                   ClutterLayoutManager *manager)
16344 {
16345   ClutterActorPrivate *priv;
16346
16347   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16348   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16349
16350   priv = self->priv;
16351
16352   if (priv->layout_manager != NULL)
16353     {
16354       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16355                                             G_CALLBACK (on_layout_manager_changed),
16356                                             self);
16357       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16358       g_clear_object (&priv->layout_manager);
16359     }
16360
16361   priv->layout_manager = manager;
16362
16363   if (priv->layout_manager != NULL)
16364     {
16365       g_object_ref_sink (priv->layout_manager);
16366       clutter_layout_manager_set_container (priv->layout_manager,
16367                                             CLUTTER_CONTAINER (self));
16368       g_signal_connect (priv->layout_manager, "layout-changed",
16369                         G_CALLBACK (on_layout_manager_changed),
16370                         self);
16371     }
16372
16373   clutter_actor_queue_relayout (self);
16374
16375   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16376 }
16377
16378 /**
16379  * clutter_actor_get_layout_manager:
16380  * @self: a #ClutterActor
16381  *
16382  * Retrieves the #ClutterLayoutManager used by @self.
16383  *
16384  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16385  *   or %NULL
16386  *
16387  * Since: 1.10
16388  */
16389 ClutterLayoutManager *
16390 clutter_actor_get_layout_manager (ClutterActor *self)
16391 {
16392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16393
16394   return self->priv->layout_manager;
16395 }
16396
16397 static const ClutterLayoutInfo default_layout_info = {
16398   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16399   { 0, 0, 0, 0 },               /* margin */
16400   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16401   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16402   FALSE, FALSE,                 /* expand */
16403   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16404   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16405 };
16406
16407 static void
16408 layout_info_free (gpointer data)
16409 {
16410   if (G_LIKELY (data != NULL))
16411     g_slice_free (ClutterLayoutInfo, data);
16412 }
16413
16414 /*< private >
16415  * _clutter_actor_peek_layout_info:
16416  * @self: a #ClutterActor
16417  *
16418  * Retrieves a pointer to the ClutterLayoutInfo structure.
16419  *
16420  * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16421  *
16422  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16423  */
16424 ClutterLayoutInfo *
16425 _clutter_actor_peek_layout_info (ClutterActor *self)
16426 {
16427   return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16428 }
16429
16430 /*< private >
16431  * _clutter_actor_get_layout_info:
16432  * @self: a #ClutterActor
16433  *
16434  * Retrieves a pointer to the ClutterLayoutInfo structure.
16435  *
16436  * If the actor does not have a ClutterLayoutInfo associated to it, one
16437  * will be created and initialized to the default values.
16438  *
16439  * This function should be used for setters.
16440  *
16441  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16442  * instead.
16443  *
16444  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16445  */
16446 ClutterLayoutInfo *
16447 _clutter_actor_get_layout_info (ClutterActor *self)
16448 {
16449   ClutterLayoutInfo *retval;
16450
16451   retval = _clutter_actor_peek_layout_info (self);
16452   if (retval == NULL)
16453     {
16454       retval = g_slice_new (ClutterLayoutInfo);
16455
16456       *retval = default_layout_info;
16457
16458       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16459                                retval,
16460                                layout_info_free);
16461     }
16462
16463   return retval;
16464 }
16465
16466 /*< private >
16467  * _clutter_actor_get_layout_info_or_defaults:
16468  * @self: a #ClutterActor
16469  *
16470  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16471  *
16472  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16473  * then the default structure will be returned.
16474  *
16475  * This function should only be used for getters.
16476  *
16477  * Return value: a const pointer to the ClutterLayoutInfo structure
16478  */
16479 const ClutterLayoutInfo *
16480 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16481 {
16482   const ClutterLayoutInfo *info;
16483
16484   info = _clutter_actor_peek_layout_info (self);
16485   if (info == NULL)
16486     return &default_layout_info;
16487
16488   return info;
16489 }
16490
16491 /**
16492  * clutter_actor_set_x_align:
16493  * @self: a #ClutterActor
16494  * @x_align: the horizontal alignment policy
16495  *
16496  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16497  * actor received extra horizontal space.
16498  *
16499  * See also the #ClutterActor:x-align property.
16500  *
16501  * Since: 1.10
16502  */
16503 void
16504 clutter_actor_set_x_align (ClutterActor      *self,
16505                            ClutterActorAlign  x_align)
16506 {
16507   ClutterLayoutInfo *info;
16508
16509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16510
16511   info = _clutter_actor_get_layout_info (self);
16512
16513   if (info->x_align != x_align)
16514     {
16515       info->x_align = x_align;
16516
16517       clutter_actor_queue_relayout (self);
16518
16519       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16520     }
16521 }
16522
16523 /**
16524  * clutter_actor_get_x_align:
16525  * @self: a #ClutterActor
16526  *
16527  * Retrieves the horizontal alignment policy set using
16528  * clutter_actor_set_x_align().
16529  *
16530  * Return value: the horizontal alignment policy.
16531  *
16532  * Since: 1.10
16533  */
16534 ClutterActorAlign
16535 clutter_actor_get_x_align (ClutterActor *self)
16536 {
16537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16538
16539   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16540 }
16541
16542 /**
16543  * clutter_actor_set_y_align:
16544  * @self: a #ClutterActor
16545  * @y_align: the vertical alignment policy
16546  *
16547  * Sets the vertical alignment policy of a #ClutterActor, in case the
16548  * actor received extra vertical space.
16549  *
16550  * See also the #ClutterActor:y-align property.
16551  *
16552  * Since: 1.10
16553  */
16554 void
16555 clutter_actor_set_y_align (ClutterActor      *self,
16556                            ClutterActorAlign  y_align)
16557 {
16558   ClutterLayoutInfo *info;
16559
16560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16561
16562   info = _clutter_actor_get_layout_info (self);
16563
16564   if (info->y_align != y_align)
16565     {
16566       info->y_align = y_align;
16567
16568       clutter_actor_queue_relayout (self);
16569
16570       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16571     }
16572 }
16573
16574 /**
16575  * clutter_actor_get_y_align:
16576  * @self: a #ClutterActor
16577  *
16578  * Retrieves the vertical alignment policy set using
16579  * clutter_actor_set_y_align().
16580  *
16581  * Return value: the vertical alignment policy.
16582  *
16583  * Since: 1.10
16584  */
16585 ClutterActorAlign
16586 clutter_actor_get_y_align (ClutterActor *self)
16587 {
16588   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16589
16590   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16591 }
16592
16593 /**
16594  * clutter_actor_set_margin:
16595  * @self: a #ClutterActor
16596  * @margin: a #ClutterMargin
16597  *
16598  * Sets all the components of the margin of a #ClutterActor.
16599  *
16600  * Since: 1.10
16601  */
16602 void
16603 clutter_actor_set_margin (ClutterActor        *self,
16604                           const ClutterMargin *margin)
16605 {
16606   ClutterLayoutInfo *info;
16607   gboolean changed;
16608   GObject *obj;
16609
16610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16611   g_return_if_fail (margin != NULL);
16612
16613   obj = G_OBJECT (self);
16614   changed = FALSE;
16615
16616   g_object_freeze_notify (obj);
16617
16618   info = _clutter_actor_get_layout_info (self);
16619
16620   if (info->margin.top != margin->top)
16621     {
16622       info->margin.top = margin->top;
16623       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16624       changed = TRUE;
16625     }
16626
16627   if (info->margin.right != margin->right)
16628     {
16629       info->margin.right = margin->right;
16630       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16631       changed = TRUE;
16632     }
16633
16634   if (info->margin.bottom != margin->bottom)
16635     {
16636       info->margin.bottom = margin->bottom;
16637       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16638       changed = TRUE;
16639     }
16640
16641   if (info->margin.left != margin->left)
16642     {
16643       info->margin.left = margin->left;
16644       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16645       changed = TRUE;
16646     }
16647
16648   if (changed)
16649     clutter_actor_queue_relayout (self);
16650
16651   g_object_thaw_notify (obj);
16652 }
16653
16654 /**
16655  * clutter_actor_get_margin:
16656  * @self: a #ClutterActor
16657  * @margin: (out caller-allocates): return location for a #ClutterMargin
16658  *
16659  * Retrieves all the components of the margin of a #ClutterActor.
16660  *
16661  * Since: 1.10
16662  */
16663 void
16664 clutter_actor_get_margin (ClutterActor  *self,
16665                           ClutterMargin *margin)
16666 {
16667   const ClutterLayoutInfo *info;
16668
16669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16670   g_return_if_fail (margin != NULL);
16671
16672   info = _clutter_actor_get_layout_info_or_defaults (self);
16673
16674   *margin = info->margin;
16675 }
16676
16677 /**
16678  * clutter_actor_set_margin_top:
16679  * @self: a #ClutterActor
16680  * @margin: the top margin
16681  *
16682  * Sets the margin from the top of a #ClutterActor.
16683  *
16684  * Since: 1.10
16685  */
16686 void
16687 clutter_actor_set_margin_top (ClutterActor *self,
16688                               gfloat        margin)
16689 {
16690   ClutterLayoutInfo *info;
16691
16692   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16693   g_return_if_fail (margin >= 0.f);
16694
16695   info = _clutter_actor_get_layout_info (self);
16696
16697   if (info->margin.top == margin)
16698     return;
16699
16700   info->margin.top = margin;
16701
16702   clutter_actor_queue_relayout (self);
16703
16704   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16705 }
16706
16707 /**
16708  * clutter_actor_get_margin_top:
16709  * @self: a #ClutterActor
16710  *
16711  * Retrieves the top margin of a #ClutterActor.
16712  *
16713  * Return value: the top margin
16714  *
16715  * Since: 1.10
16716  */
16717 gfloat
16718 clutter_actor_get_margin_top (ClutterActor *self)
16719 {
16720   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16721
16722   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16723 }
16724
16725 /**
16726  * clutter_actor_set_margin_bottom:
16727  * @self: a #ClutterActor
16728  * @margin: the bottom margin
16729  *
16730  * Sets the margin from the bottom of a #ClutterActor.
16731  *
16732  * Since: 1.10
16733  */
16734 void
16735 clutter_actor_set_margin_bottom (ClutterActor *self,
16736                                  gfloat        margin)
16737 {
16738   ClutterLayoutInfo *info;
16739
16740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16741   g_return_if_fail (margin >= 0.f);
16742
16743   info = _clutter_actor_get_layout_info (self);
16744
16745   if (info->margin.bottom == margin)
16746     return;
16747
16748   info->margin.bottom = margin;
16749
16750   clutter_actor_queue_relayout (self);
16751
16752   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16753 }
16754
16755 /**
16756  * clutter_actor_get_margin_bottom:
16757  * @self: a #ClutterActor
16758  *
16759  * Retrieves the bottom margin of a #ClutterActor.
16760  *
16761  * Return value: the bottom margin
16762  *
16763  * Since: 1.10
16764  */
16765 gfloat
16766 clutter_actor_get_margin_bottom (ClutterActor *self)
16767 {
16768   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16769
16770   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16771 }
16772
16773 /**
16774  * clutter_actor_set_margin_left:
16775  * @self: a #ClutterActor
16776  * @margin: the left margin
16777  *
16778  * Sets the margin from the left of a #ClutterActor.
16779  *
16780  * Since: 1.10
16781  */
16782 void
16783 clutter_actor_set_margin_left (ClutterActor *self,
16784                                gfloat        margin)
16785 {
16786   ClutterLayoutInfo *info;
16787
16788   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16789   g_return_if_fail (margin >= 0.f);
16790
16791   info = _clutter_actor_get_layout_info (self);
16792
16793   if (info->margin.left == margin)
16794     return;
16795
16796   info->margin.left = margin;
16797
16798   clutter_actor_queue_relayout (self);
16799
16800   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16801 }
16802
16803 /**
16804  * clutter_actor_get_margin_left:
16805  * @self: a #ClutterActor
16806  *
16807  * Retrieves the left margin of a #ClutterActor.
16808  *
16809  * Return value: the left margin
16810  *
16811  * Since: 1.10
16812  */
16813 gfloat
16814 clutter_actor_get_margin_left (ClutterActor *self)
16815 {
16816   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16817
16818   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16819 }
16820
16821 /**
16822  * clutter_actor_set_margin_right:
16823  * @self: a #ClutterActor
16824  * @margin: the right margin
16825  *
16826  * Sets the margin from the right of a #ClutterActor.
16827  *
16828  * Since: 1.10
16829  */
16830 void
16831 clutter_actor_set_margin_right (ClutterActor *self,
16832                                 gfloat        margin)
16833 {
16834   ClutterLayoutInfo *info;
16835
16836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16837   g_return_if_fail (margin >= 0.f);
16838
16839   info = _clutter_actor_get_layout_info (self);
16840
16841   if (info->margin.right == margin)
16842     return;
16843
16844   info->margin.right = margin;
16845
16846   clutter_actor_queue_relayout (self);
16847
16848   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16849 }
16850
16851 /**
16852  * clutter_actor_get_margin_right:
16853  * @self: a #ClutterActor
16854  *
16855  * Retrieves the right margin of a #ClutterActor.
16856  *
16857  * Return value: the right margin
16858  *
16859  * Since: 1.10
16860  */
16861 gfloat
16862 clutter_actor_get_margin_right (ClutterActor *self)
16863 {
16864   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16865
16866   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16867 }
16868
16869 static inline void
16870 clutter_actor_set_background_color_internal (ClutterActor *self,
16871                                              const ClutterColor *color)
16872 {
16873   ClutterActorPrivate *priv = self->priv;
16874   GObject *obj;
16875
16876   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16877     return;
16878
16879   obj = G_OBJECT (self);
16880
16881   priv->bg_color = *color;
16882   priv->bg_color_set = TRUE;
16883
16884   clutter_actor_queue_redraw (self);
16885
16886   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16887   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16888 }
16889
16890 /**
16891  * clutter_actor_set_background_color:
16892  * @self: a #ClutterActor
16893  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16894  *  set color
16895  *
16896  * Sets the background color of a #ClutterActor.
16897  *
16898  * The background color will be used to cover the whole allocation of the
16899  * actor. The default background color of an actor is transparent.
16900  *
16901  * To check whether an actor has a background color, you can use the
16902  * #ClutterActor:background-color-set actor property.
16903  *
16904  * The #ClutterActor:background-color property is animatable.
16905  *
16906  * Since: 1.10
16907  */
16908 void
16909 clutter_actor_set_background_color (ClutterActor       *self,
16910                                     const ClutterColor *color)
16911 {
16912   ClutterActorPrivate *priv;
16913   GObject *obj;
16914   GParamSpec *bg_color_pspec;
16915
16916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16917
16918   obj = G_OBJECT (self);
16919
16920   priv = self->priv;
16921
16922   if (color == NULL)
16923     {
16924       priv->bg_color_set = FALSE;
16925       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16926       clutter_actor_queue_redraw (self);
16927       return;
16928     }
16929
16930   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16931   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16932     {
16933       _clutter_actor_create_transition (self, bg_color_pspec,
16934                                         &priv->bg_color,
16935                                         color);
16936     }
16937   else
16938     _clutter_actor_update_transition (self, bg_color_pspec, color);
16939
16940   clutter_actor_queue_redraw (self);
16941 }
16942
16943 /**
16944  * clutter_actor_get_background_color:
16945  * @self: a #ClutterActor
16946  * @color: (out caller-allocates): return location for a #ClutterColor
16947  *
16948  * Retrieves the color set using clutter_actor_set_background_color().
16949  *
16950  * Since: 1.10
16951  */
16952 void
16953 clutter_actor_get_background_color (ClutterActor *self,
16954                                     ClutterColor *color)
16955 {
16956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16957   g_return_if_fail (color != NULL);
16958
16959   *color = self->priv->bg_color;
16960 }
16961
16962 /**
16963  * clutter_actor_get_previous_sibling:
16964  * @self: a #ClutterActor
16965  *
16966  * Retrieves the sibling of @self that comes before it in the list
16967  * of children of @self's parent.
16968  *
16969  * The returned pointer is only valid until the scene graph changes; it
16970  * is not safe to modify the list of children of @self while iterating
16971  * it.
16972  *
16973  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16974  *
16975  * Since: 1.10
16976  */
16977 ClutterActor *
16978 clutter_actor_get_previous_sibling (ClutterActor *self)
16979 {
16980   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16981
16982   return self->priv->prev_sibling;
16983 }
16984
16985 /**
16986  * clutter_actor_get_next_sibling:
16987  * @self: a #ClutterActor
16988  *
16989  * Retrieves the sibling of @self that comes after it in the list
16990  * of children of @self's parent.
16991  *
16992  * The returned pointer is only valid until the scene graph changes; it
16993  * is not safe to modify the list of children of @self while iterating
16994  * it.
16995  *
16996  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16997  *
16998  * Since: 1.10
16999  */
17000 ClutterActor *
17001 clutter_actor_get_next_sibling (ClutterActor *self)
17002 {
17003   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17004
17005   return self->priv->next_sibling;
17006 }
17007
17008 /**
17009  * clutter_actor_get_first_child:
17010  * @self: a #ClutterActor
17011  *
17012  * Retrieves the first child of @self.
17013  *
17014  * The returned pointer is only valid until the scene graph changes; it
17015  * is not safe to modify the list of children of @self while iterating
17016  * it.
17017  *
17018  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17019  *
17020  * Since: 1.10
17021  */
17022 ClutterActor *
17023 clutter_actor_get_first_child (ClutterActor *self)
17024 {
17025   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17026
17027   return self->priv->first_child;
17028 }
17029
17030 /**
17031  * clutter_actor_get_last_child:
17032  * @self: a #ClutterActor
17033  *
17034  * Retrieves the last child of @self.
17035  *
17036  * The returned pointer is only valid until the scene graph changes; it
17037  * is not safe to modify the list of children of @self while iterating
17038  * it.
17039  *
17040  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17041  *
17042  * Since: 1.10
17043  */
17044 ClutterActor *
17045 clutter_actor_get_last_child (ClutterActor *self)
17046 {
17047   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17048
17049   return self->priv->last_child;
17050 }
17051
17052 /* easy way to have properly named fields instead of the dummy ones
17053  * we use in the public structure
17054  */
17055 typedef struct _RealActorIter
17056 {
17057   ClutterActor *root;           /* dummy1 */
17058   ClutterActor *current;        /* dummy2 */
17059   gpointer padding_1;           /* dummy3 */
17060   gint age;                     /* dummy4 */
17061   gpointer padding_2;           /* dummy5 */
17062 } RealActorIter;
17063
17064 /**
17065  * clutter_actor_iter_init:
17066  * @iter: a #ClutterActorIter
17067  * @root: a #ClutterActor
17068  *
17069  * Initializes a #ClutterActorIter, which can then be used to iterate
17070  * efficiently over a section of the scene graph, and associates it
17071  * with @root.
17072  *
17073  * Modifying the scene graph section that contains @root will invalidate
17074  * the iterator.
17075  *
17076  * |[
17077  *   ClutterActorIter iter;
17078  *   ClutterActor *child;
17079  *
17080  *   clutter_actor_iter_init (&iter, container);
17081  *   while (clutter_actor_iter_next (&iter, &child))
17082  *     {
17083  *       /&ast; do something with child &ast;/
17084  *     }
17085  * ]|
17086  *
17087  * Since: 1.10
17088  */
17089 void
17090 clutter_actor_iter_init (ClutterActorIter *iter,
17091                          ClutterActor     *root)
17092 {
17093   RealActorIter *ri = (RealActorIter *) iter;
17094
17095   g_return_if_fail (iter != NULL);
17096   g_return_if_fail (CLUTTER_IS_ACTOR (root));
17097
17098   ri->root = root;
17099   ri->current = NULL;
17100   ri->age = root->priv->age;
17101 }
17102
17103 /**
17104  * clutter_actor_iter_next:
17105  * @iter: a #ClutterActorIter
17106  * @child: (out): return location for a #ClutterActor
17107  *
17108  * Advances the @iter and retrieves the next child of the root #ClutterActor
17109  * that was used to initialize the #ClutterActorIterator.
17110  *
17111  * If the iterator can advance, this function returns %TRUE and sets the
17112  * @child argument.
17113  *
17114  * If the iterator cannot advance, this function returns %FALSE, and
17115  * the contents of @child are undefined.
17116  *
17117  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17118  *
17119  * Since: 1.10
17120  */
17121 gboolean
17122 clutter_actor_iter_next (ClutterActorIter  *iter,
17123                          ClutterActor     **child)
17124 {
17125   RealActorIter *ri = (RealActorIter *) iter;
17126
17127   g_return_val_if_fail (iter != NULL, FALSE);
17128   g_return_val_if_fail (ri->root != NULL, FALSE);
17129 #ifndef G_DISABLE_ASSERT
17130   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17131 #endif
17132
17133   if (ri->current == NULL)
17134     ri->current = ri->root->priv->first_child;
17135   else
17136     ri->current = ri->current->priv->next_sibling;
17137
17138   if (child != NULL)
17139     *child = ri->current;
17140
17141   return ri->current != NULL;
17142 }
17143
17144 /**
17145  * clutter_actor_iter_prev:
17146  * @iter: a #ClutterActorIter
17147  * @child: (out): return location for a #ClutterActor
17148  *
17149  * Advances the @iter and retrieves the previous child of the root
17150  * #ClutterActor that was used to initialize the #ClutterActorIterator.
17151  *
17152  * If the iterator can advance, this function returns %TRUE and sets the
17153  * @child argument.
17154  *
17155  * If the iterator cannot advance, this function returns %FALSE, and
17156  * the contents of @child are undefined.
17157  *
17158  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17159  *
17160  * Since: 1.10
17161  */
17162 gboolean
17163 clutter_actor_iter_prev (ClutterActorIter  *iter,
17164                          ClutterActor     **child)
17165 {
17166   RealActorIter *ri = (RealActorIter *) iter;
17167
17168   g_return_val_if_fail (iter != NULL, FALSE);
17169   g_return_val_if_fail (ri->root != NULL, FALSE);
17170 #ifndef G_DISABLE_ASSERT
17171   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17172 #endif
17173
17174   if (ri->current == NULL)
17175     ri->current = ri->root->priv->last_child;
17176   else
17177     ri->current = ri->current->priv->prev_sibling;
17178
17179   if (child != NULL)
17180     *child = ri->current;
17181
17182   return ri->current != NULL;
17183 }
17184
17185 /**
17186  * clutter_actor_iter_remove:
17187  * @iter: a #ClutterActorIter
17188  *
17189  * Safely removes the #ClutterActor currently pointer to by the iterator
17190  * from its parent.
17191  *
17192  * This function can only be called after clutter_actor_iter_next() or
17193  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17194  * than once for the same actor.
17195  *
17196  * This function will call clutter_actor_remove_child() internally.
17197  *
17198  * Since: 1.10
17199  */
17200 void
17201 clutter_actor_iter_remove (ClutterActorIter *iter)
17202 {
17203   RealActorIter *ri = (RealActorIter *) iter;
17204   ClutterActor *cur;
17205
17206   g_return_if_fail (iter != NULL);
17207   g_return_if_fail (ri->root != NULL);
17208 #ifndef G_DISABLE_ASSERT
17209   g_return_if_fail (ri->age == ri->root->priv->age);
17210 #endif
17211   g_return_if_fail (ri->current != NULL);
17212
17213   cur = ri->current;
17214
17215   if (cur != NULL)
17216     {
17217       ri->current = cur->priv->prev_sibling;
17218
17219       clutter_actor_remove_child_internal (ri->root, cur,
17220                                            REMOVE_CHILD_DEFAULT_FLAGS);
17221
17222       ri->age += 1;
17223     }
17224 }
17225
17226 /**
17227  * clutter_actor_iter_destroy:
17228  * @iter: a #ClutterActorIter
17229  *
17230  * Safely destroys the #ClutterActor currently pointer to by the iterator
17231  * from its parent.
17232  *
17233  * This function can only be called after clutter_actor_iter_next() or
17234  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17235  * than once for the same actor.
17236  *
17237  * This function will call clutter_actor_destroy() internally.
17238  *
17239  * Since: 1.10
17240  */
17241 void
17242 clutter_actor_iter_destroy (ClutterActorIter *iter)
17243 {
17244   RealActorIter *ri = (RealActorIter *) iter;
17245   ClutterActor *cur;
17246
17247   g_return_if_fail (iter != NULL);
17248   g_return_if_fail (ri->root != NULL);
17249 #ifndef G_DISABLE_ASSERT
17250   g_return_if_fail (ri->age == ri->root->priv->age);
17251 #endif
17252   g_return_if_fail (ri->current != NULL);
17253
17254   cur = ri->current;
17255
17256   if (cur != NULL)
17257     {
17258       ri->current = cur->priv->prev_sibling;
17259
17260       clutter_actor_destroy (cur);
17261
17262       ri->age += 1;
17263     }
17264 }
17265
17266 static const ClutterAnimationInfo default_animation_info = {
17267   NULL,         /* transitions */
17268   NULL,         /* states */
17269   NULL,         /* cur_state */
17270 };
17271
17272 static void
17273 clutter_animation_info_free (gpointer data)
17274 {
17275   if (data != NULL)
17276     {
17277       ClutterAnimationInfo *info = data;
17278
17279       if (info->transitions != NULL)
17280         g_hash_table_unref (info->transitions);
17281
17282       if (info->states != NULL)
17283         g_array_unref (info->states);
17284
17285       g_slice_free (ClutterAnimationInfo, info);
17286     }
17287 }
17288
17289 const ClutterAnimationInfo *
17290 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17291 {
17292   const ClutterAnimationInfo *res;
17293   GObject *obj = G_OBJECT (self);
17294
17295   res = g_object_get_qdata (obj, quark_actor_animation_info);
17296   if (res != NULL)
17297     return res;
17298
17299   return &default_animation_info;
17300 }
17301
17302 ClutterAnimationInfo *
17303 _clutter_actor_get_animation_info (ClutterActor *self)
17304 {
17305   GObject *obj = G_OBJECT (self);
17306   ClutterAnimationInfo *res;
17307
17308   res = g_object_get_qdata (obj, quark_actor_animation_info);
17309   if (res == NULL)
17310     {
17311       res = g_slice_new (ClutterAnimationInfo);
17312
17313       *res = default_animation_info;
17314
17315       g_object_set_qdata_full (obj, quark_actor_animation_info,
17316                                res,
17317                                clutter_animation_info_free);
17318     }
17319
17320   return res;
17321 }
17322
17323 ClutterTransition *
17324 _clutter_actor_get_transition (ClutterActor *actor,
17325                                GParamSpec   *pspec)
17326 {
17327   const ClutterAnimationInfo *info;
17328
17329   info = _clutter_actor_get_animation_info_or_defaults (actor);
17330
17331   if (info->transitions == NULL)
17332     return NULL;
17333
17334   return g_hash_table_lookup (info->transitions, pspec->name);
17335 }
17336
17337 static void
17338 transition_closure_free (gpointer data)
17339 {
17340   if (G_LIKELY (data != NULL))
17341     {
17342       TransitionClosure *clos = data;
17343       ClutterTimeline *timeline;
17344
17345       timeline = CLUTTER_TIMELINE (clos->transition);
17346
17347       if (clutter_timeline_is_playing (timeline))
17348         clutter_timeline_stop (timeline);
17349
17350       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17351
17352       g_object_unref (clos->transition);
17353       g_free (clos->name);
17354
17355       g_slice_free (TransitionClosure, clos);
17356     }
17357 }
17358
17359 static void
17360 on_transition_stopped (ClutterTransition *transition,
17361                        gboolean           is_finished,
17362                        TransitionClosure *clos)
17363 {
17364   ClutterActor *actor = clos->actor;
17365   ClutterAnimationInfo *info;
17366
17367   /* reset the caches used by animations */
17368   clutter_actor_store_content_box (actor, NULL);
17369
17370   if (!is_finished)
17371     return;
17372
17373   info = _clutter_actor_get_animation_info (actor);
17374
17375   /* we take a reference here because removing the closure
17376    * will release the reference on the transition, and we
17377    * want the transition to survive the signal emission;
17378    * the master clock will release the last reference at
17379    * the end of the frame processing.
17380    */
17381   g_object_ref (transition);
17382   g_hash_table_remove (info->transitions, clos->name);
17383
17384   /* if it's the last transition then we clean up */
17385   if (g_hash_table_size (info->transitions) == 0)
17386     {
17387       g_hash_table_unref (info->transitions);
17388       info->transitions = NULL;
17389
17390       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17391                     _clutter_actor_get_debug_name (actor));
17392
17393       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17394     }
17395 }
17396
17397 void
17398 _clutter_actor_update_transition (ClutterActor *actor,
17399                                   GParamSpec   *pspec,
17400                                   ...)
17401 {
17402   TransitionClosure *clos;
17403   ClutterTimeline *timeline;
17404   ClutterInterval *interval;
17405   const ClutterAnimationInfo *info;
17406   va_list var_args;
17407   GType ptype;
17408   GValue initial = G_VALUE_INIT;
17409   GValue final = G_VALUE_INIT;
17410   char *error = NULL;
17411
17412   info = _clutter_actor_get_animation_info_or_defaults (actor);
17413
17414   if (info->transitions == NULL)
17415     return;
17416
17417   clos = g_hash_table_lookup (info->transitions, pspec->name);
17418   if (clos == NULL)
17419     return;
17420
17421   timeline = CLUTTER_TIMELINE (clos->transition);
17422
17423   va_start (var_args, pspec);
17424
17425   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17426
17427   g_value_init (&initial, ptype);
17428   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17429                                         pspec->name,
17430                                         &initial);
17431
17432   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17433   if (error != NULL)
17434     {
17435       g_critical ("%s: %s", G_STRLOC, error);
17436       g_free (error);
17437       goto out;
17438     }
17439
17440   interval = clutter_transition_get_interval (clos->transition);
17441   clutter_interval_set_initial_value (interval, &initial);
17442   clutter_interval_set_final_value (interval, &final);
17443
17444   /* if we're updating with an easing duration of zero milliseconds,
17445    * we just jump the timeline to the end and let it run its course
17446    */
17447   if (info->cur_state != NULL &&
17448       info->cur_state->easing_duration != 0)
17449     {
17450       guint cur_duration = clutter_timeline_get_duration (timeline);
17451       ClutterAnimationMode cur_mode =
17452         clutter_timeline_get_progress_mode (timeline);
17453
17454       if (cur_duration != info->cur_state->easing_duration)
17455         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17456
17457       if (cur_mode != info->cur_state->easing_mode)
17458         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17459
17460       clutter_timeline_rewind (timeline);
17461     }
17462   else
17463     {
17464       guint duration = clutter_timeline_get_duration (timeline);
17465
17466       clutter_timeline_advance (timeline, duration);
17467     }
17468
17469 out:
17470   g_value_unset (&initial);
17471   g_value_unset (&final);
17472
17473   va_end (var_args);
17474 }
17475
17476 /*< private >*
17477  * _clutter_actor_create_transition:
17478  * @actor: a #ClutterActor
17479  * @pspec: the property used for the transition
17480  * @...: initial and final state
17481  *
17482  * Creates a #ClutterTransition for the property represented by @pspec.
17483  *
17484  * Return value: a #ClutterTransition
17485  */
17486 ClutterTransition *
17487 _clutter_actor_create_transition (ClutterActor *actor,
17488                                   GParamSpec   *pspec,
17489                                   ...)
17490 {
17491   ClutterAnimationInfo *info;
17492   ClutterTransition *res = NULL;
17493   gboolean call_restore = FALSE;
17494   TransitionClosure *clos;
17495   va_list var_args;
17496
17497   info = _clutter_actor_get_animation_info (actor);
17498
17499   /* XXX - this will go away in 2.0
17500    *
17501    * if no state has been pushed, we assume that the easing state is
17502    * in "compatibility mode": all transitions have a duration of 0
17503    * msecs, which means that they happen immediately. in Clutter 2.0
17504    * this will turn into a g_assert(info->states != NULL), as every
17505    * actor will start with a predefined easing state
17506    */
17507   if (info->states == NULL)
17508     {
17509       clutter_actor_save_easing_state (actor);
17510       clutter_actor_set_easing_duration (actor, 0);
17511       call_restore = TRUE;
17512     }
17513
17514   if (info->transitions == NULL)
17515     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17516                                                NULL,
17517                                                transition_closure_free);
17518
17519   va_start (var_args, pspec);
17520
17521   clos = g_hash_table_lookup (info->transitions, pspec->name);
17522   if (clos == NULL)
17523     {
17524       ClutterTimeline *timeline;
17525       ClutterInterval *interval;
17526       GValue initial = G_VALUE_INIT;
17527       GValue final = G_VALUE_INIT;
17528       GType ptype;
17529       char *error;
17530
17531       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17532
17533       G_VALUE_COLLECT_INIT (&initial, ptype,
17534                             var_args, 0,
17535                             &error);
17536       if (error != NULL)
17537         {
17538           g_critical ("%s: %s", G_STRLOC, error);
17539           g_free (error);
17540           goto out;
17541         }
17542
17543       G_VALUE_COLLECT_INIT (&final, ptype,
17544                             var_args, 0,
17545                             &error);
17546
17547       if (error != NULL)
17548         {
17549           g_critical ("%s: %s", G_STRLOC, error);
17550           g_value_unset (&initial);
17551           g_free (error);
17552           goto out;
17553         }
17554
17555       /* if the current easing state has a duration of 0, then we don't
17556        * bother to create the transition, and we just set the final value
17557        * directly on the actor; we don't go through the Animatable
17558        * interface because we know we got here through an animatable
17559        * property.
17560        */
17561       if (info->cur_state->easing_duration == 0)
17562         {
17563           clutter_actor_set_animatable_property (actor,
17564                                                  pspec->param_id,
17565                                                  &final,
17566                                                  pspec);
17567           g_value_unset (&initial);
17568           g_value_unset (&final);
17569
17570           goto out;
17571         }
17572
17573       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17574
17575       g_value_unset (&initial);
17576       g_value_unset (&final);
17577
17578       res = clutter_property_transition_new (pspec->name);
17579
17580       clutter_transition_set_interval (res, interval);
17581       clutter_transition_set_remove_on_complete (res, TRUE);
17582
17583       timeline = CLUTTER_TIMELINE (res);
17584       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17585       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17586       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17587
17588       CLUTTER_NOTE (ANIMATION,
17589                     "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17590                     _clutter_actor_get_debug_name (actor),
17591                     pspec->name,
17592                     info->cur_state->easing_duration,
17593                     clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17594                     info->cur_state->easing_delay);
17595
17596       /* this will start the transition as well */
17597       clutter_actor_add_transition (actor, pspec->name, res);
17598
17599       /* the actor now owns the transition */
17600       g_object_unref (res);
17601     }
17602   else
17603     res = clos->transition;
17604
17605 out:
17606   if (call_restore)
17607     clutter_actor_restore_easing_state (actor);
17608
17609   va_end (var_args);
17610
17611   return res;
17612 }
17613
17614 /**
17615  * clutter_actor_add_transition:
17616  * @self: a #ClutterActor
17617  * @name: the name of the transition to add
17618  * @transition: the #ClutterTransition to add
17619  *
17620  * Adds a @transition to the #ClutterActor's list of animations.
17621  *
17622  * The @name string is a per-actor unique identifier of the @transition: only
17623  * one #ClutterTransition can be associated to the specified @name.
17624  *
17625  * The @transition will be started once added.
17626  *
17627  * This function will take a reference on the @transition.
17628  *
17629  * This function is usually called implicitly when modifying an animatable
17630  * property.
17631  *
17632  * Since: 1.10
17633  */
17634 void
17635 clutter_actor_add_transition (ClutterActor      *self,
17636                               const char        *name,
17637                               ClutterTransition *transition)
17638 {
17639   ClutterTimeline *timeline;
17640   TransitionClosure *clos;
17641   ClutterAnimationInfo *info;
17642
17643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17644   g_return_if_fail (name != NULL);
17645   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17646
17647   info = _clutter_actor_get_animation_info (self);
17648
17649   if (info->transitions == NULL)
17650     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17651                                                NULL,
17652                                                transition_closure_free);
17653
17654   if (g_hash_table_lookup (info->transitions, name) != NULL)
17655     {
17656       g_warning ("A transition with name '%s' already exists for "
17657                  "the actor '%s'",
17658                  name,
17659                  _clutter_actor_get_debug_name (self));
17660       return;
17661     }
17662
17663   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17664
17665   timeline = CLUTTER_TIMELINE (transition);
17666
17667   clos = g_slice_new (TransitionClosure);
17668   clos->actor = self;
17669   clos->transition = g_object_ref (transition);
17670   clos->name = g_strdup (name);
17671   clos->completed_id = g_signal_connect (timeline, "stopped",
17672                                          G_CALLBACK (on_transition_stopped),
17673                                          clos);
17674
17675   CLUTTER_NOTE (ANIMATION,
17676                 "Adding transition '%s' [%p] to actor '%s'",
17677                 clos->name,
17678                 clos->transition,
17679                 _clutter_actor_get_debug_name (self));
17680
17681   g_hash_table_insert (info->transitions, clos->name, clos);
17682   clutter_timeline_start (timeline);
17683 }
17684
17685 /**
17686  * clutter_actor_remove_transition:
17687  * @self: a #ClutterActor
17688  * @name: the name of the transition to remove
17689  *
17690  * Removes the transition stored inside a #ClutterActor using @name
17691  * identifier.
17692  *
17693  * If the transition is currently in progress, it will be stopped.
17694  *
17695  * This function releases the reference acquired when the transition
17696  * was added to the #ClutterActor.
17697  *
17698  * Since: 1.10
17699  */
17700 void
17701 clutter_actor_remove_transition (ClutterActor *self,
17702                                  const char   *name)
17703 {
17704   const ClutterAnimationInfo *info;
17705
17706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17707   g_return_if_fail (name != NULL);
17708
17709   info = _clutter_actor_get_animation_info_or_defaults (self);
17710
17711   if (info->transitions == NULL)
17712     return;
17713
17714   g_hash_table_remove (info->transitions, name);
17715 }
17716
17717 /**
17718  * clutter_actor_remove_all_transitions:
17719  * @self: a #ClutterActor
17720  *
17721  * Removes all transitions associated to @self.
17722  *
17723  * Since: 1.10
17724  */
17725 void
17726 clutter_actor_remove_all_transitions (ClutterActor *self)
17727 {
17728   const ClutterAnimationInfo *info;
17729
17730   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17731
17732   info = _clutter_actor_get_animation_info_or_defaults (self);
17733   if (info->transitions == NULL)
17734     return;
17735
17736   g_hash_table_remove_all (info->transitions);
17737 }
17738
17739 /**
17740  * clutter_actor_set_easing_duration:
17741  * @self: a #ClutterActor
17742  * @msecs: the duration of the easing, or %NULL
17743  *
17744  * Sets the duration of the tweening for animatable properties
17745  * of @self for the current easing state.
17746  *
17747  * Since: 1.10
17748  */
17749 void
17750 clutter_actor_set_easing_duration (ClutterActor *self,
17751                                    guint         msecs)
17752 {
17753   ClutterAnimationInfo *info;
17754
17755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17756
17757   info = _clutter_actor_get_animation_info (self);
17758
17759   if (info->cur_state == NULL)
17760     {
17761       g_warning ("You must call clutter_actor_save_easing_state() prior "
17762                  "to calling clutter_actor_set_easing_duration().");
17763       return;
17764     }
17765
17766   if (info->cur_state->easing_duration != msecs)
17767     info->cur_state->easing_duration = msecs;
17768 }
17769
17770 /**
17771  * clutter_actor_get_easing_duration:
17772  * @self: a #ClutterActor
17773  *
17774  * Retrieves the duration of the tweening for animatable
17775  * properties of @self for the current easing state.
17776  *
17777  * Return value: the duration of the tweening, in milliseconds
17778  *
17779  * Since: 1.10
17780  */
17781 guint
17782 clutter_actor_get_easing_duration (ClutterActor *self)
17783 {
17784   const ClutterAnimationInfo *info;
17785
17786   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17787
17788   info = _clutter_actor_get_animation_info_or_defaults (self);
17789
17790   if (info->cur_state != NULL)
17791     return info->cur_state->easing_duration;
17792
17793   return 0;
17794 }
17795
17796 /**
17797  * clutter_actor_set_easing_mode:
17798  * @self: a #ClutterActor
17799  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17800  *
17801  * Sets the easing mode for the tweening of animatable properties
17802  * of @self.
17803  *
17804  * Since: 1.10
17805  */
17806 void
17807 clutter_actor_set_easing_mode (ClutterActor         *self,
17808                                ClutterAnimationMode  mode)
17809 {
17810   ClutterAnimationInfo *info;
17811
17812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17813   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17814   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17815
17816   info = _clutter_actor_get_animation_info (self);
17817
17818   if (info->cur_state == NULL)
17819     {
17820       g_warning ("You must call clutter_actor_save_easing_state() prior "
17821                  "to calling clutter_actor_set_easing_mode().");
17822       return;
17823     }
17824
17825   if (info->cur_state->easing_mode != mode)
17826     info->cur_state->easing_mode = mode;
17827 }
17828
17829 /**
17830  * clutter_actor_get_easing_mode:
17831  * @self: a #ClutterActor
17832  *
17833  * Retrieves the easing mode for the tweening of animatable properties
17834  * of @self for the current easing state.
17835  *
17836  * Return value: an easing mode
17837  *
17838  * Since: 1.10
17839  */
17840 ClutterAnimationMode
17841 clutter_actor_get_easing_mode (ClutterActor *self)
17842 {
17843   const ClutterAnimationInfo *info;
17844
17845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17846
17847   info = _clutter_actor_get_animation_info_or_defaults (self);
17848
17849   if (info->cur_state != NULL)
17850     return info->cur_state->easing_mode;
17851
17852   return CLUTTER_EASE_OUT_CUBIC;
17853 }
17854
17855 /**
17856  * clutter_actor_set_easing_delay:
17857  * @self: a #ClutterActor
17858  * @msecs: the delay before the start of the tweening, in milliseconds
17859  *
17860  * Sets the delay that should be applied before tweening animatable
17861  * properties.
17862  *
17863  * Since: 1.10
17864  */
17865 void
17866 clutter_actor_set_easing_delay (ClutterActor *self,
17867                                 guint         msecs)
17868 {
17869   ClutterAnimationInfo *info;
17870
17871   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17872
17873   info = _clutter_actor_get_animation_info (self);
17874
17875   if (info->cur_state == NULL)
17876     {
17877       g_warning ("You must call clutter_actor_save_easing_state() prior "
17878                  "to calling clutter_actor_set_easing_delay().");
17879       return;
17880     }
17881
17882   if (info->cur_state->easing_delay != msecs)
17883     info->cur_state->easing_delay = msecs;
17884 }
17885
17886 /**
17887  * clutter_actor_get_easing_delay:
17888  * @self: a #ClutterActor
17889  *
17890  * Retrieves the delay that should be applied when tweening animatable
17891  * properties.
17892  *
17893  * Return value: a delay, in milliseconds
17894  *
17895  * Since: 1.10
17896  */
17897 guint
17898 clutter_actor_get_easing_delay (ClutterActor *self)
17899 {
17900   const ClutterAnimationInfo *info;
17901
17902   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17903
17904   info = _clutter_actor_get_animation_info_or_defaults (self);
17905
17906   if (info->cur_state != NULL)
17907     return info->cur_state->easing_delay;
17908
17909   return 0;
17910 }
17911
17912 /**
17913  * clutter_actor_get_transition:
17914  * @self: a #ClutterActor
17915  * @name: the name of the transition
17916  *
17917  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17918  * transition @name.
17919  *
17920  * Transitions created for animatable properties use the name of the
17921  * property itself, for instance the code below:
17922  *
17923  * |[
17924  *   clutter_actor_set_easing_duration (actor, 1000);
17925  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17926  *
17927  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17928  *   g_signal_connect (transition, "stopped",
17929  *                     G_CALLBACK (on_transition_stopped),
17930  *                     actor);
17931  * ]|
17932  *
17933  * will call the <function>on_transition_stopped</function> callback when
17934  * the transition is finished.
17935  *
17936  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17937  *   was found to match the passed name; the returned instance is owned
17938  *   by Clutter and it should not be freed
17939  *
17940  * Since: 1.10
17941  */
17942 ClutterTransition *
17943 clutter_actor_get_transition (ClutterActor *self,
17944                               const char   *name)
17945 {
17946   TransitionClosure *clos;
17947   const ClutterAnimationInfo *info;
17948
17949   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17950   g_return_val_if_fail (name != NULL, NULL);
17951
17952   info = _clutter_actor_get_animation_info_or_defaults (self);
17953   if (info->transitions == NULL)
17954     return NULL;
17955
17956   clos = g_hash_table_lookup (info->transitions, name);
17957   if (clos == NULL)
17958     return NULL;
17959
17960   return clos->transition;
17961 }
17962
17963 /**
17964  * clutter_actor_save_easing_state:
17965  * @self: a #ClutterActor
17966  *
17967  * Saves the current easing state for animatable properties, and creates
17968  * a new state with the default values for easing mode and duration.
17969  *
17970  * Since: 1.10
17971  */
17972 void
17973 clutter_actor_save_easing_state (ClutterActor *self)
17974 {
17975   ClutterAnimationInfo *info;
17976   AState new_state;
17977
17978   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17979
17980   info = _clutter_actor_get_animation_info (self);
17981
17982   if (info->states == NULL)
17983     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17984
17985   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17986   new_state.easing_duration = 250;
17987   new_state.easing_delay = 0;
17988
17989   g_array_append_val (info->states, new_state);
17990
17991   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17992 }
17993
17994 /**
17995  * clutter_actor_restore_easing_state:
17996  * @self: a #ClutterActor
17997  *
17998  * Restores the easing state as it was prior to a call to
17999  * clutter_actor_save_easing_state().
18000  *
18001  * Since: 1.10
18002  */
18003 void
18004 clutter_actor_restore_easing_state (ClutterActor *self)
18005 {
18006   ClutterAnimationInfo *info;
18007
18008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18009
18010   info = _clutter_actor_get_animation_info (self);
18011
18012   if (info->states == NULL)
18013     {
18014       g_critical ("The function clutter_actor_restore_easing_state() has "
18015                   "called without a previous call to "
18016                   "clutter_actor_save_easing_state().");
18017       return;
18018     }
18019
18020   g_array_remove_index (info->states, info->states->len - 1);
18021
18022   if (info->states->len > 0)
18023     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
18024   else
18025     {
18026       g_array_unref (info->states);
18027       info->states = NULL;
18028       info->cur_state = NULL;
18029     }
18030 }
18031
18032 /**
18033  * clutter_actor_set_content:
18034  * @self: a #ClutterActor
18035  * @content: (allow-none): a #ClutterContent, or %NULL
18036  *
18037  * Sets the contents of a #ClutterActor.
18038  *
18039  * Since: 1.10
18040  */
18041 void
18042 clutter_actor_set_content (ClutterActor   *self,
18043                            ClutterContent *content)
18044 {
18045   ClutterActorPrivate *priv;
18046
18047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18048   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18049
18050   priv = self->priv;
18051
18052   if (priv->content != NULL)
18053     {
18054       _clutter_content_detached (priv->content, self);
18055       g_clear_object (&priv->content);
18056     }
18057
18058   priv->content = content;
18059
18060   if (priv->content != NULL)
18061     {
18062       g_object_ref (priv->content);
18063       _clutter_content_attached (priv->content, self);
18064     }
18065
18066   /* given that the content is always painted within the allocation,
18067    * we only need to queue a redraw here
18068    */
18069   clutter_actor_queue_redraw (self);
18070
18071   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18072
18073   /* if the content gravity is not resize-fill, and the new content has a
18074    * different preferred size than the previous one, then the content box
18075    * may have been changed. since we compute that lazily, we just notify
18076    * here, and let whomever watches :content-box do whatever they need to
18077    * do.
18078    */
18079   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18080     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18081 }
18082
18083 /**
18084  * clutter_actor_get_content:
18085  * @self: a #ClutterActor
18086  *
18087  * Retrieves the contents of @self.
18088  *
18089  * Return value: (transfer none): a pointer to the #ClutterContent instance,
18090  *   or %NULL if none was set
18091  *
18092  * Since: 1.10
18093  */
18094 ClutterContent *
18095 clutter_actor_get_content (ClutterActor *self)
18096 {
18097   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18098
18099   return self->priv->content;
18100 }
18101
18102 /**
18103  * clutter_actor_set_content_gravity:
18104  * @self: a #ClutterActor
18105  * @gravity: the #ClutterContentGravity
18106  *
18107  * Sets the gravity of the #ClutterContent used by @self.
18108  *
18109  * See the description of the #ClutterActor:content-gravity property for
18110  * more information.
18111  *
18112  * The #ClutterActor:content-gravity property is animatable.
18113  *
18114  * Since: 1.10
18115  */
18116 void
18117 clutter_actor_set_content_gravity (ClutterActor *self,
18118                                    ClutterContentGravity  gravity)
18119 {
18120   ClutterActorPrivate *priv;
18121
18122   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18123
18124   priv = self->priv;
18125
18126   if (priv->content_gravity == gravity)
18127     return;
18128
18129   priv->content_box_valid = FALSE;
18130
18131   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18132     {
18133       ClutterActorBox from_box, to_box;
18134
18135       clutter_actor_get_content_box (self, &from_box);
18136
18137       priv->content_gravity = gravity;
18138
18139       clutter_actor_get_content_box (self, &to_box);
18140
18141       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18142                                         &from_box,
18143                                         &to_box);
18144     }
18145   else
18146     {
18147       ClutterActorBox to_box;
18148
18149       priv->content_gravity = gravity;
18150
18151       clutter_actor_get_content_box (self, &to_box);
18152
18153       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18154                                         &to_box);
18155     }
18156
18157   clutter_actor_queue_redraw (self);
18158
18159   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18160 }
18161
18162 /**
18163  * clutter_actor_get_content_gravity:
18164  * @self: a #ClutterActor
18165  *
18166  * Retrieves the content gravity as set using
18167  * clutter_actor_get_content_gravity().
18168  *
18169  * Return value: the content gravity
18170  *
18171  * Since: 1.10
18172  */
18173 ClutterContentGravity
18174 clutter_actor_get_content_gravity (ClutterActor *self)
18175 {
18176   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18177                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18178
18179   return self->priv->content_gravity;
18180 }
18181
18182 /**
18183  * clutter_actor_get_content_box:
18184  * @self: a #ClutterActor
18185  * @box: (out caller-allocates): the return location for the bounding
18186  *   box for the #ClutterContent
18187  *
18188  * Retrieves the bounding box for the #ClutterContent of @self.
18189  *
18190  * The bounding box is relative to the actor's allocation.
18191  *
18192  * If no #ClutterContent is set for @self, or if @self has not been
18193  * allocated yet, then the result is undefined.
18194  *
18195  * The content box is guaranteed to be, at most, as big as the allocation
18196  * of the #ClutterActor.
18197  *
18198  * If the #ClutterContent used by the actor has a preferred size, then
18199  * it is possible to modify the content box by using the
18200  * #ClutterActor:content-gravity property.
18201  *
18202  * Since: 1.10
18203  */
18204 void
18205 clutter_actor_get_content_box (ClutterActor    *self,
18206                                ClutterActorBox *box)
18207 {
18208   ClutterActorPrivate *priv;
18209   gfloat content_w, content_h;
18210   gfloat alloc_w, alloc_h;
18211
18212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18213   g_return_if_fail (box != NULL);
18214
18215   priv = self->priv;
18216
18217   box->x1 = 0.f;
18218   box->y1 = 0.f;
18219   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18220   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18221
18222   if (priv->content_box_valid)
18223     {
18224       *box = priv->content_box;
18225       return;
18226     }
18227
18228   /* no need to do any more work */
18229   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18230     return;
18231
18232   if (priv->content == NULL)
18233     return;
18234
18235   /* if the content does not have a preferred size then there is
18236    * no point in computing the content box
18237    */
18238   if (!clutter_content_get_preferred_size (priv->content,
18239                                            &content_w,
18240                                            &content_h))
18241     return;
18242
18243   alloc_w = box->x2;
18244   alloc_h = box->y2;
18245
18246   switch (priv->content_gravity)
18247     {
18248     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18249       box->x2 = box->x1 + MIN (content_w, alloc_w);
18250       box->y2 = box->y1 + MIN (content_h, alloc_h);
18251       break;
18252
18253     case CLUTTER_CONTENT_GRAVITY_TOP:
18254       if (alloc_w > content_w)
18255         {
18256           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18257           box->x2 = box->x1 + content_w;
18258         }
18259       box->y2 = box->y1 + MIN (content_h, alloc_h);
18260       break;
18261
18262     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18263       if (alloc_w > content_w)
18264         {
18265           box->x1 += (alloc_w - content_w);
18266           box->x2 = box->x1 + content_w;
18267         }
18268       box->y2 = box->y1 + MIN (content_h, alloc_h);
18269       break;
18270
18271     case CLUTTER_CONTENT_GRAVITY_LEFT:
18272       box->x2 = box->x1 + MIN (content_w, alloc_w);
18273       if (alloc_h > content_h)
18274         {
18275           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18276           box->y2 = box->y1 + content_h;
18277         }
18278       break;
18279
18280     case CLUTTER_CONTENT_GRAVITY_CENTER:
18281       if (alloc_w > content_w)
18282         {
18283           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18284           box->x2 = box->x1 + content_w;
18285         }
18286       if (alloc_h > content_h)
18287         {
18288           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18289           box->y2 = box->y1 + content_h;
18290         }
18291       break;
18292
18293     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18294       if (alloc_w > content_w)
18295         {
18296           box->x1 += (alloc_w - content_w);
18297           box->x2 = box->x1 + content_w;
18298         }
18299       if (alloc_h > content_h)
18300         {
18301           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18302           box->y2 = box->y1 + content_h;
18303         }
18304       break;
18305
18306     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18307       box->x2 = box->x1 + MIN (content_w, alloc_w);
18308       if (alloc_h > content_h)
18309         {
18310           box->y1 += (alloc_h - content_h);
18311           box->y2 = box->y1 + content_h;
18312         }
18313       break;
18314
18315     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18316       if (alloc_w > content_w)
18317         {
18318           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18319           box->x2 = box->x1 + content_w;
18320         }
18321       if (alloc_h > content_h)
18322         {
18323           box->y1 += (alloc_h - content_h);
18324           box->y2 = box->y1 + content_h;
18325         }
18326       break;
18327
18328     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18329       if (alloc_w > content_w)
18330         {
18331           box->x1 += (alloc_w - content_w);
18332           box->x2 = box->x1 + content_w;
18333         }
18334       if (alloc_h > content_h)
18335         {
18336           box->y1 += (alloc_h - content_h);
18337           box->y2 = box->y1 + content_h;
18338         }
18339       break;
18340
18341     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18342       g_assert_not_reached ();
18343       break;
18344
18345     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18346       {
18347         double r_c = content_w / content_h;
18348
18349         if (r_c >= 1.0)
18350           {
18351             if ((alloc_w / r_c) > alloc_h)
18352               {
18353                 box->x1 = 0.f;
18354                 box->x2 = alloc_w;
18355
18356                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18357                 box->y2 = box->y1 + (alloc_w / r_c);
18358               }
18359             else
18360               {
18361                 box->y1 = 0.f;
18362                 box->y2 = alloc_h;
18363
18364                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18365                 box->x2 = box->x1 + (alloc_h * r_c);
18366               }
18367           }
18368         else
18369           {
18370             if ((alloc_w / r_c) > alloc_h)
18371               {
18372                 box->y1 = 0.f;
18373                 box->y2 = alloc_h;
18374
18375                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18376                 box->x2 = box->x1 + (alloc_h * r_c);
18377               }
18378             else
18379               {
18380                 box->x1 = 0.f;
18381                 box->x2 = alloc_w;
18382
18383                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18384                 box->y2 = box->y1 + (alloc_w / r_c);
18385               }
18386           }
18387
18388         CLUTTER_NOTE (LAYOUT,
18389                       "r_c: %.3f, r_a: %.3f\t"
18390                       "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18391                       "b: [%.2f, %.2f, %.2f, %.2f]",
18392                       r_c, alloc_w / alloc_h,
18393                       alloc_w, alloc_h,
18394                       content_w, content_h,
18395                       box->x1, box->y1, box->x2, box->y2);
18396       }
18397       break;
18398     }
18399 }
18400
18401 /**
18402  * clutter_actor_set_content_scaling_filters:
18403  * @self: a #ClutterActor
18404  * @min_filter: the minification filter for the content
18405  * @mag_filter: the magnification filter for the content
18406  *
18407  * Sets the minification and magnification filter to be applied when
18408  * scaling the #ClutterActor:content of a #ClutterActor.
18409  *
18410  * The #ClutterActor:minification-filter will be used when reducing
18411  * the size of the content; the #ClutterActor:magnification-filter
18412  * will be used when increasing the size of the content.
18413  *
18414  * Since: 1.10
18415  */
18416 void
18417 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18418                                            ClutterScalingFilter  min_filter,
18419                                            ClutterScalingFilter  mag_filter)
18420 {
18421   ClutterActorPrivate *priv;
18422   gboolean changed;
18423   GObject *obj;
18424
18425   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18426
18427   priv = self->priv;
18428   obj = G_OBJECT (self);
18429
18430   g_object_freeze_notify (obj);
18431
18432   changed = FALSE;
18433
18434   if (priv->min_filter != min_filter)
18435     {
18436       priv->min_filter = min_filter;
18437       changed = TRUE;
18438
18439       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18440     }
18441
18442   if (priv->mag_filter != mag_filter)
18443     {
18444       priv->mag_filter = mag_filter;
18445       changed = TRUE;
18446
18447       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18448     }
18449
18450   if (changed)
18451     clutter_actor_queue_redraw (self);
18452
18453   g_object_thaw_notify (obj);
18454 }
18455
18456 /**
18457  * clutter_actor_get_content_scaling_filters:
18458  * @self: a #ClutterActor
18459  * @min_filter: (out) (allow-none): return location for the minification
18460  *   filter, or %NULL
18461  * @mag_filter: (out) (allow-none): return location for the magnification
18462  *   filter, or %NULL
18463  *
18464  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18465  *
18466  * Since: 1.10
18467  */
18468 void
18469 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18470                                            ClutterScalingFilter *min_filter,
18471                                            ClutterScalingFilter *mag_filter)
18472 {
18473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18474
18475   if (min_filter != NULL)
18476     *min_filter = self->priv->min_filter;
18477
18478   if (mag_filter != NULL)
18479     *mag_filter = self->priv->mag_filter;
18480 }
18481
18482 /*
18483  * clutter_actor_queue_compute_expand:
18484  * @self: a #ClutterActor
18485  *
18486  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18487  * and its parents up to the top-level actor.
18488  *
18489  * This function also queues a relayout if anything changed.
18490  */
18491 static inline void
18492 clutter_actor_queue_compute_expand (ClutterActor *self)
18493 {
18494   ClutterActor *parent;
18495   gboolean changed;
18496
18497   if (self->priv->needs_compute_expand)
18498     return;
18499
18500   changed = FALSE;
18501   parent = self;
18502   while (parent != NULL)
18503     {
18504       if (!parent->priv->needs_compute_expand)
18505         {
18506           parent->priv->needs_compute_expand = TRUE;
18507           changed = TRUE;
18508         }
18509
18510       parent = parent->priv->parent;
18511     }
18512
18513   if (changed)
18514     clutter_actor_queue_relayout (self);
18515 }
18516
18517 /**
18518  * clutter_actor_set_x_expand:
18519  * @self: a #ClutterActor
18520  * @expand: whether the actor should expand horizontally
18521  *
18522  * Sets whether a #ClutterActor should expand horizontally; this means
18523  * that layout manager should allocate extra space for the actor, if
18524  * possible.
18525  *
18526  * Setting an actor to expand will also make all its parent expand, so
18527  * that it's possible to build an actor tree and only set this flag on
18528  * its leaves and not on every single actor.
18529  *
18530  * Since: 1.12
18531  */
18532 void
18533 clutter_actor_set_x_expand (ClutterActor *self,
18534                             gboolean      expand)
18535 {
18536   ClutterLayoutInfo *info;
18537
18538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18539
18540   expand = !!expand;
18541
18542   info = _clutter_actor_get_layout_info (self);
18543   if (info->x_expand != expand)
18544     {
18545       info->x_expand = expand;
18546
18547       self->priv->x_expand_set = TRUE;
18548
18549       clutter_actor_queue_compute_expand (self);
18550
18551       g_object_notify_by_pspec (G_OBJECT (self),
18552                                 obj_props[PROP_X_EXPAND]);
18553     }
18554 }
18555
18556 /**
18557  * clutter_actor_get_x_expand:
18558  * @self: a #ClutterActor
18559  *
18560  * Retrieves the value set with clutter_actor_set_x_expand().
18561  *
18562  * See also: clutter_actor_needs_expand()
18563  *
18564  * Return value: %TRUE if the actor has been set to expand
18565  *
18566  * Since: 1.12
18567  */
18568 gboolean
18569 clutter_actor_get_x_expand (ClutterActor *self)
18570 {
18571   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18572
18573   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18574 }
18575
18576 /**
18577  * clutter_actor_set_y_expand:
18578  * @self: a #ClutterActor
18579  * @expand: whether the actor should expand vertically
18580  *
18581  * Sets whether a #ClutterActor should expand horizontally; this means
18582  * that layout manager should allocate extra space for the actor, if
18583  * possible.
18584  *
18585  * Setting an actor to expand will also make all its parent expand, so
18586  * that it's possible to build an actor tree and only set this flag on
18587  * its leaves and not on every single actor.
18588  *
18589  * Since: 1.12
18590  */
18591 void
18592 clutter_actor_set_y_expand (ClutterActor *self,
18593                             gboolean      expand)
18594 {
18595   ClutterLayoutInfo *info;
18596
18597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18598
18599   expand = !!expand;
18600
18601   info = _clutter_actor_get_layout_info (self);
18602   if (info->y_expand != expand)
18603     {
18604       info->y_expand = expand;
18605
18606       self->priv->y_expand_set = TRUE;
18607
18608       clutter_actor_queue_compute_expand (self);
18609
18610       g_object_notify_by_pspec (G_OBJECT (self),
18611                                 obj_props[PROP_Y_EXPAND]);
18612     }
18613 }
18614
18615 /**
18616  * clutter_actor_get_y_expand:
18617  * @self: a #ClutterActor
18618  *
18619  * Retrieves the value set with clutter_actor_set_y_expand().
18620  *
18621  * See also: clutter_actor_needs_expand()
18622  *
18623  * Return value: %TRUE if the actor has been set to expand
18624  *
18625  * Since: 1.12
18626  */
18627 gboolean
18628 clutter_actor_get_y_expand (ClutterActor *self)
18629 {
18630   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18631
18632   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18633 }
18634
18635 static void
18636 clutter_actor_compute_expand_recursive (ClutterActor *self,
18637                                         gboolean     *x_expand_p,
18638                                         gboolean     *y_expand_p)
18639 {
18640   ClutterActorIter iter;
18641   ClutterActor *child;
18642   gboolean x_expand, y_expand;
18643
18644   x_expand = y_expand = FALSE;
18645
18646   /* note that we don't recurse into children if we're already set to expand;
18647    * this avoids traversing the whole actor tree, even if it may lead to some
18648    * child left with the needs_compute_expand flag set.
18649    */
18650   clutter_actor_iter_init (&iter, self);
18651   while (clutter_actor_iter_next (&iter, &child))
18652     {
18653       x_expand = x_expand ||
18654         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18655
18656       y_expand = y_expand ||
18657         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18658     }
18659
18660   *x_expand_p = x_expand;
18661   *y_expand_p = y_expand;
18662 }
18663
18664 static void
18665 clutter_actor_compute_expand (ClutterActor *self)
18666 {
18667   if (self->priv->needs_compute_expand)
18668     {
18669       const ClutterLayoutInfo *info;
18670       gboolean x_expand, y_expand;
18671
18672       info = _clutter_actor_get_layout_info_or_defaults (self);
18673
18674       if (self->priv->x_expand_set)
18675         x_expand = info->x_expand;
18676       else
18677         x_expand = FALSE;
18678
18679       if (self->priv->y_expand_set)
18680         y_expand = info->y_expand;
18681       else
18682         y_expand = FALSE;
18683
18684       /* we don't need to recurse down to the children if the
18685        * actor has been forcibly set to expand
18686        */
18687       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18688         {
18689           if (self->priv->n_children != 0)
18690             {
18691               gboolean *x_expand_p, *y_expand_p;
18692               gboolean ignored = FALSE;
18693
18694               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18695               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18696
18697               clutter_actor_compute_expand_recursive (self,
18698                                                       x_expand_p,
18699                                                       y_expand_p);
18700             }
18701         }
18702
18703       self->priv->needs_compute_expand = FALSE;
18704       self->priv->needs_x_expand = (x_expand != FALSE);
18705       self->priv->needs_y_expand = (y_expand != FALSE);
18706     }
18707 }
18708
18709 /**
18710  * clutter_actor_needs_expand:
18711  * @self: a #ClutterActor
18712  * @orientation: the direction of expansion
18713  *
18714  * Checks whether an actor, or any of its children, is set to expand
18715  * horizontally or vertically.
18716  *
18717  * This function should only be called by layout managers that can
18718  * assign extra space to their children.
18719  *
18720  * If you want to know whether the actor was explicitly set to expand,
18721  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18722  *
18723  * Return value: %TRUE if the actor should expand
18724  *
18725  * Since: 1.12
18726  */
18727 gboolean
18728 clutter_actor_needs_expand (ClutterActor       *self,
18729                             ClutterOrientation  orientation)
18730 {
18731   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18732
18733   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18734     return FALSE;
18735
18736   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18737     return FALSE;
18738
18739   clutter_actor_compute_expand (self);
18740
18741   switch (orientation)
18742     {
18743     case CLUTTER_ORIENTATION_HORIZONTAL:
18744       return self->priv->needs_x_expand;
18745
18746     case CLUTTER_ORIENTATION_VERTICAL:
18747       return self->priv->needs_y_expand;
18748     }
18749
18750   return FALSE;
18751 }
18752
18753 /**
18754  * clutter_actor_set_content_repeat:
18755  * @self: a #ClutterActor
18756  * @repeat: the repeat policy
18757  *
18758  * Sets the policy for repeating the #ClutterActor:content of a
18759  * #ClutterActor. The behaviour is deferred to the #ClutterContent
18760  * implementation.
18761  *
18762  * Since: 1.12
18763  */
18764 void
18765 clutter_actor_set_content_repeat (ClutterActor         *self,
18766                                   ClutterContentRepeat  repeat)
18767 {
18768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18769
18770   if (self->priv->content_repeat == repeat)
18771     return;
18772
18773   self->priv->content_repeat = repeat;
18774
18775   clutter_actor_queue_redraw (self);
18776 }
18777
18778 /**
18779  * clutter_actor_get_content_repeat:
18780  * @self: a #ClutterActor
18781  *
18782  * Retrieves the repeat policy for a #ClutterActor set by
18783  * clutter_actor_set_content_repeat().
18784  *
18785  * Return value: the content repeat policy
18786  *
18787  * Since: 1.12
18788  */
18789 ClutterContentRepeat
18790 clutter_actor_get_content_repeat (ClutterActor *self)
18791 {
18792   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REPEAT_NONE);
18793
18794   return self->priv->content_repeat;
18795 }