actor: Provide an initial easing state
[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_actor_restore_easing_state (CLUTTER_ACTOR (object));
5309
5310   _clutter_context_release_id (priv->id);
5311
5312   g_free (priv->name);
5313
5314 #ifdef CLUTTER_ENABLE_DEBUG
5315   g_free (priv->debug_name);
5316 #endif
5317
5318   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5319 }
5320
5321
5322 /**
5323  * clutter_actor_get_accessible:
5324  * @self: a #ClutterActor
5325  *
5326  * Returns the accessible object that describes the actor to an
5327  * assistive technology.
5328  *
5329  * If no class-specific #AtkObject implementation is available for the
5330  * actor instance in question, it will inherit an #AtkObject
5331  * implementation from the first ancestor class for which such an
5332  * implementation is defined.
5333  *
5334  * The documentation of the <ulink
5335  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5336  * library contains more information about accessible objects and
5337  * their uses.
5338  *
5339  * Returns: (transfer none): the #AtkObject associated with @actor
5340  */
5341 AtkObject *
5342 clutter_actor_get_accessible (ClutterActor *self)
5343 {
5344   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5345
5346   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5347 }
5348
5349 static AtkObject *
5350 clutter_actor_real_get_accessible (ClutterActor *actor)
5351 {
5352   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5353 }
5354
5355 static AtkObject *
5356 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5357 {
5358   AtkObject *accessible;
5359
5360   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5361   if (accessible != NULL)
5362     g_object_ref (accessible);
5363
5364   return accessible;
5365 }
5366
5367 static void
5368 atk_implementor_iface_init (AtkImplementorIface *iface)
5369 {
5370   iface->ref_accessible = _clutter_actor_ref_accessible;
5371 }
5372
5373 static gboolean
5374 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5375                                            ClutterPaintVolume *volume)
5376 {
5377   ClutterActorPrivate *priv = self->priv;
5378   gboolean res = TRUE;
5379
5380   /* we start from the allocation */
5381   clutter_paint_volume_set_width (volume,
5382                                   priv->allocation.x2 - priv->allocation.x1);
5383   clutter_paint_volume_set_height (volume,
5384                                    priv->allocation.y2 - priv->allocation.y1);
5385
5386   /* if the actor has a clip set then we have a pretty definite
5387    * size for the paint volume: the actor cannot possibly paint
5388    * outside the clip region.
5389    */
5390   if (priv->clip_to_allocation)
5391     {
5392       /* the allocation has already been set, so we just flip the
5393        * return value
5394        */
5395       res = TRUE;
5396     }
5397   else
5398     {
5399       ClutterActor *child;
5400
5401       if (priv->has_clip &&
5402           priv->clip.width >= 0 &&
5403           priv->clip.height >= 0)
5404         {
5405           ClutterVertex origin;
5406
5407           origin.x = priv->clip.x;
5408           origin.y = priv->clip.y;
5409           origin.z = 0;
5410
5411           clutter_paint_volume_set_origin (volume, &origin);
5412           clutter_paint_volume_set_width (volume, priv->clip.width);
5413           clutter_paint_volume_set_height (volume, priv->clip.height);
5414
5415           res = TRUE;
5416         }
5417
5418       /* if we don't have children we just bail out here... */
5419       if (priv->n_children == 0)
5420         return res;
5421
5422       /* ...but if we have children then we ask for their paint volume in
5423        * our coordinates. if any of our children replies that it doesn't
5424        * have a paint volume, we bail out
5425        */
5426       for (child = priv->first_child;
5427            child != NULL;
5428            child = child->priv->next_sibling)
5429         {
5430           const ClutterPaintVolume *child_volume;
5431
5432           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5433             continue;
5434
5435           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5436           if (child_volume == NULL)
5437             {
5438               res = FALSE;
5439               break;
5440             }
5441
5442           clutter_paint_volume_union (volume, child_volume);
5443           res = TRUE;
5444         }
5445     }
5446
5447   return res;
5448
5449 }
5450
5451 static gboolean
5452 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5453                                      ClutterPaintVolume *volume)
5454 {
5455   ClutterActorClass *klass;
5456   gboolean res;
5457
5458   klass = CLUTTER_ACTOR_GET_CLASS (self);
5459
5460   /* XXX - this thoroughly sucks, but we don't want to penalize users
5461    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5462    * redraw. This should go away in 2.0.
5463    */
5464   if (klass->paint == clutter_actor_real_paint &&
5465       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5466     {
5467       res = TRUE;
5468     }
5469   else
5470     {
5471       /* this is the default return value: we cannot know if a class
5472        * is going to paint outside its allocation, so we take the
5473        * conservative approach.
5474        */
5475       res = FALSE;
5476     }
5477
5478   /* update_default_paint_volume() should only fail if one of the children
5479    * reported an invalid, or no, paint volume
5480    */
5481   if (!clutter_actor_update_default_paint_volume (self, volume))
5482     return FALSE;
5483
5484   return res;
5485 }
5486
5487 /**
5488  * clutter_actor_get_default_paint_volume:
5489  * @self: a #ClutterActor
5490  *
5491  * Retrieves the default paint volume for @self.
5492  *
5493  * This function provides the same #ClutterPaintVolume that would be
5494  * computed by the default implementation inside #ClutterActor of the
5495  * #ClutterActorClass.get_paint_volume() virtual function.
5496  *
5497  * This function should only be used by #ClutterActor subclasses that
5498  * cannot chain up to the parent implementation when computing their
5499  * paint volume.
5500  *
5501  * Return value: (transfer none): a pointer to the default
5502  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5503  *   the actor could not compute a valid paint volume. The returned value
5504  *   is not guaranteed to be stable across multiple frames, so if you
5505  *   want to retain it, you will need to copy it using
5506  *   clutter_paint_volume_copy().
5507  *
5508  * Since: 1.10
5509  */
5510 const ClutterPaintVolume *
5511 clutter_actor_get_default_paint_volume (ClutterActor *self)
5512 {
5513   ClutterPaintVolume volume;
5514   ClutterPaintVolume *res;
5515
5516   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5517
5518   res = NULL;
5519   _clutter_paint_volume_init_static (&volume, self);
5520   if (clutter_actor_update_default_paint_volume (self, &volume))
5521     {
5522       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5523
5524       if (stage != NULL)
5525         {
5526           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5527           _clutter_paint_volume_copy_static (&volume, res);
5528         }
5529     }
5530
5531   clutter_paint_volume_free (&volume);
5532
5533   return res;
5534 }
5535
5536 static gboolean
5537 clutter_actor_real_has_overlaps (ClutterActor *self)
5538 {
5539   /* By default we'll assume that all actors need an offscreen redirect to get
5540    * the correct opacity. Actors such as ClutterTexture that would never need
5541    * an offscreen redirect can override this to return FALSE. */
5542   return TRUE;
5543 }
5544
5545 static void
5546 clutter_actor_real_destroy (ClutterActor *actor)
5547 {
5548   ClutterActorIter iter;
5549
5550   g_object_freeze_notify (G_OBJECT (actor));
5551
5552   clutter_actor_iter_init (&iter, actor);
5553   while (clutter_actor_iter_next (&iter, NULL))
5554     clutter_actor_iter_destroy (&iter);
5555
5556   g_object_thaw_notify (G_OBJECT (actor));
5557 }
5558
5559 static GObject *
5560 clutter_actor_constructor (GType gtype,
5561                            guint n_props,
5562                            GObjectConstructParam *props)
5563 {
5564   GObjectClass *gobject_class;
5565   ClutterActor *self;
5566   GObject *retval;
5567
5568   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5569   retval = gobject_class->constructor (gtype, n_props, props);
5570   self = CLUTTER_ACTOR (retval);
5571
5572   if (self->priv->layout_manager == NULL)
5573     {
5574       ClutterLayoutManager *default_layout;
5575
5576       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5577
5578       default_layout = clutter_fixed_layout_new ();
5579       clutter_actor_set_layout_manager (self, default_layout);
5580     }
5581
5582   return retval;
5583 }
5584
5585 static void
5586 clutter_actor_class_init (ClutterActorClass *klass)
5587 {
5588   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5589
5590   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5591   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5592   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5593   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5594
5595   object_class->constructor = clutter_actor_constructor;
5596   object_class->set_property = clutter_actor_set_property;
5597   object_class->get_property = clutter_actor_get_property;
5598   object_class->dispose = clutter_actor_dispose;
5599   object_class->finalize = clutter_actor_finalize;
5600
5601   klass->show = clutter_actor_real_show;
5602   klass->show_all = clutter_actor_show;
5603   klass->hide = clutter_actor_real_hide;
5604   klass->hide_all = clutter_actor_hide;
5605   klass->map = clutter_actor_real_map;
5606   klass->unmap = clutter_actor_real_unmap;
5607   klass->unrealize = clutter_actor_real_unrealize;
5608   klass->pick = clutter_actor_real_pick;
5609   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5610   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5611   klass->allocate = clutter_actor_real_allocate;
5612   klass->queue_redraw = clutter_actor_real_queue_redraw;
5613   klass->queue_relayout = clutter_actor_real_queue_relayout;
5614   klass->apply_transform = clutter_actor_real_apply_transform;
5615   klass->get_accessible = clutter_actor_real_get_accessible;
5616   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5617   klass->has_overlaps = clutter_actor_real_has_overlaps;
5618   klass->paint = clutter_actor_real_paint;
5619   klass->destroy = clutter_actor_real_destroy;
5620
5621   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5622
5623   /**
5624    * ClutterActor:x:
5625    *
5626    * X coordinate of the actor in pixels. If written, forces a fixed
5627    * position for the actor. If read, returns the fixed position if any,
5628    * otherwise the allocation if available, otherwise 0.
5629    *
5630    * The #ClutterActor:x property is animatable.
5631    */
5632   obj_props[PROP_X] =
5633     g_param_spec_float ("x",
5634                         P_("X coordinate"),
5635                         P_("X coordinate of the actor"),
5636                         -G_MAXFLOAT, G_MAXFLOAT,
5637                         0.0,
5638                         G_PARAM_READWRITE |
5639                         G_PARAM_STATIC_STRINGS |
5640                         CLUTTER_PARAM_ANIMATABLE);
5641
5642   /**
5643    * ClutterActor:y:
5644    *
5645    * Y coordinate of the actor in pixels. If written, forces a fixed
5646    * position for the actor.  If read, returns the fixed position if
5647    * any, otherwise the allocation if available, otherwise 0.
5648    *
5649    * The #ClutterActor:y property is animatable.
5650    */
5651   obj_props[PROP_Y] =
5652     g_param_spec_float ("y",
5653                         P_("Y coordinate"),
5654                         P_("Y coordinate of the actor"),
5655                         -G_MAXFLOAT, G_MAXFLOAT,
5656                         0.0,
5657                         G_PARAM_READWRITE |
5658                         G_PARAM_STATIC_STRINGS |
5659                         CLUTTER_PARAM_ANIMATABLE);
5660
5661   /**
5662    * ClutterActor:position:
5663    *
5664    * The position of the origin of the actor.
5665    *
5666    * This property is a shorthand for setting and getting the
5667    * #ClutterActor:x and #ClutterActor:y properties at the same
5668    * time.
5669    *
5670    * The #ClutterActor:position property is animatable.
5671    *
5672    * Since: 1.12
5673    */
5674   obj_props[PROP_POSITION] =
5675     g_param_spec_boxed ("position",
5676                         P_("Position"),
5677                         P_("The position of the origin of the actor"),
5678                         CLUTTER_TYPE_POINT,
5679                         G_PARAM_READWRITE |
5680                         G_PARAM_STATIC_STRINGS |
5681                         CLUTTER_PARAM_ANIMATABLE);
5682
5683   /**
5684    * ClutterActor:width:
5685    *
5686    * Width of the actor (in pixels). If written, forces the minimum and
5687    * natural size request of the actor to the given width. If read, returns
5688    * the allocated width if available, otherwise the width request.
5689    *
5690    * The #ClutterActor:width property is animatable.
5691    */
5692   obj_props[PROP_WIDTH] =
5693     g_param_spec_float ("width",
5694                         P_("Width"),
5695                         P_("Width of the actor"),
5696                         0.0, G_MAXFLOAT,
5697                         0.0,
5698                         G_PARAM_READWRITE |
5699                         G_PARAM_STATIC_STRINGS |
5700                         CLUTTER_PARAM_ANIMATABLE);
5701
5702   /**
5703    * ClutterActor:height:
5704    *
5705    * Height of the actor (in pixels).  If written, forces the minimum and
5706    * natural size request of the actor to the given height. If read, returns
5707    * the allocated height if available, otherwise the height request.
5708    *
5709    * The #ClutterActor:height property is animatable.
5710    */
5711   obj_props[PROP_HEIGHT] =
5712     g_param_spec_float ("height",
5713                         P_("Height"),
5714                         P_("Height of the actor"),
5715                         0.0, G_MAXFLOAT,
5716                         0.0,
5717                         G_PARAM_READWRITE |
5718                         G_PARAM_STATIC_STRINGS |
5719                         CLUTTER_PARAM_ANIMATABLE);
5720
5721   /**
5722    * ClutterActor:size:
5723    *
5724    * The size of the actor.
5725    *
5726    * This property is a shorthand for setting and getting the
5727    * #ClutterActor:width and #ClutterActor:height at the same time.
5728    *
5729    * The #ClutterActor:size property is animatable.
5730    *
5731    * Since: 1.12
5732    */
5733   obj_props[PROP_SIZE] =
5734     g_param_spec_boxed ("size",
5735                         P_("Size"),
5736                         P_("The size of the actor"),
5737                         CLUTTER_TYPE_SIZE,
5738                         G_PARAM_READWRITE |
5739                         G_PARAM_STATIC_STRINGS |
5740                         CLUTTER_PARAM_ANIMATABLE);
5741
5742   /**
5743    * ClutterActor:fixed-x:
5744    *
5745    * The fixed X position of the actor in pixels.
5746    *
5747    * Writing this property sets #ClutterActor:fixed-position-set
5748    * property as well, as a side effect
5749    *
5750    * Since: 0.8
5751    */
5752   obj_props[PROP_FIXED_X] =
5753     g_param_spec_float ("fixed-x",
5754                         P_("Fixed X"),
5755                         P_("Forced X position of the actor"),
5756                         -G_MAXFLOAT, G_MAXFLOAT,
5757                         0.0,
5758                         CLUTTER_PARAM_READWRITE);
5759
5760   /**
5761    * ClutterActor:fixed-y:
5762    *
5763    * The fixed Y position of the actor in pixels.
5764    *
5765    * Writing this property sets the #ClutterActor:fixed-position-set
5766    * property as well, as a side effect
5767    *
5768    * Since: 0.8
5769    */
5770   obj_props[PROP_FIXED_Y] =
5771     g_param_spec_float ("fixed-y",
5772                         P_("Fixed Y"),
5773                         P_("Forced Y position of the actor"),
5774                         -G_MAXFLOAT, G_MAXFLOAT,
5775                         0,
5776                         CLUTTER_PARAM_READWRITE);
5777
5778   /**
5779    * ClutterActor:fixed-position-set:
5780    *
5781    * This flag controls whether the #ClutterActor:fixed-x and
5782    * #ClutterActor:fixed-y properties are used
5783    *
5784    * Since: 0.8
5785    */
5786   obj_props[PROP_FIXED_POSITION_SET] =
5787     g_param_spec_boolean ("fixed-position-set",
5788                           P_("Fixed position set"),
5789                           P_("Whether to use fixed positioning for the actor"),
5790                           FALSE,
5791                           CLUTTER_PARAM_READWRITE);
5792
5793   /**
5794    * ClutterActor:min-width:
5795    *
5796    * A forced minimum width request for the actor, in pixels
5797    *
5798    * Writing this property sets the #ClutterActor:min-width-set property
5799    * as well, as a side effect.
5800    *
5801    *This property overrides the usual width request of the actor.
5802    *
5803    * Since: 0.8
5804    */
5805   obj_props[PROP_MIN_WIDTH] =
5806     g_param_spec_float ("min-width",
5807                         P_("Min Width"),
5808                         P_("Forced minimum width request for the actor"),
5809                         0.0, G_MAXFLOAT,
5810                         0.0,
5811                         CLUTTER_PARAM_READWRITE);
5812
5813   /**
5814    * ClutterActor:min-height:
5815    *
5816    * A forced minimum height request for the actor, in pixels
5817    *
5818    * Writing this property sets the #ClutterActor:min-height-set property
5819    * as well, as a side effect. This property overrides the usual height
5820    * request of the actor.
5821    *
5822    * Since: 0.8
5823    */
5824   obj_props[PROP_MIN_HEIGHT] =
5825     g_param_spec_float ("min-height",
5826                         P_("Min Height"),
5827                         P_("Forced minimum height request for the actor"),
5828                         0.0, G_MAXFLOAT,
5829                         0.0,
5830                         CLUTTER_PARAM_READWRITE);
5831
5832   /**
5833    * ClutterActor:natural-width:
5834    *
5835    * A forced natural width request for the actor, in pixels
5836    *
5837    * Writing this property sets the #ClutterActor:natural-width-set
5838    * property as well, as a side effect. This property overrides the
5839    * usual width request of the actor
5840    *
5841    * Since: 0.8
5842    */
5843   obj_props[PROP_NATURAL_WIDTH] =
5844     g_param_spec_float ("natural-width",
5845                         P_("Natural Width"),
5846                         P_("Forced natural width request for the actor"),
5847                         0.0, G_MAXFLOAT,
5848                         0.0,
5849                         CLUTTER_PARAM_READWRITE);
5850
5851   /**
5852    * ClutterActor:natural-height:
5853    *
5854    * A forced natural height request for the actor, in pixels
5855    *
5856    * Writing this property sets the #ClutterActor:natural-height-set
5857    * property as well, as a side effect. This property overrides the
5858    * usual height request of the actor
5859    *
5860    * Since: 0.8
5861    */
5862   obj_props[PROP_NATURAL_HEIGHT] =
5863     g_param_spec_float ("natural-height",
5864                         P_("Natural Height"),
5865                         P_("Forced natural height request for the actor"),
5866                         0.0, G_MAXFLOAT,
5867                         0.0,
5868                         CLUTTER_PARAM_READWRITE);
5869
5870   /**
5871    * ClutterActor:min-width-set:
5872    *
5873    * This flag controls whether the #ClutterActor:min-width property
5874    * is used
5875    *
5876    * Since: 0.8
5877    */
5878   obj_props[PROP_MIN_WIDTH_SET] =
5879     g_param_spec_boolean ("min-width-set",
5880                           P_("Minimum width set"),
5881                           P_("Whether to use the min-width property"),
5882                           FALSE,
5883                           CLUTTER_PARAM_READWRITE);
5884
5885   /**
5886    * ClutterActor:min-height-set:
5887    *
5888    * This flag controls whether the #ClutterActor:min-height property
5889    * is used
5890    *
5891    * Since: 0.8
5892    */
5893   obj_props[PROP_MIN_HEIGHT_SET] =
5894     g_param_spec_boolean ("min-height-set",
5895                           P_("Minimum height set"),
5896                           P_("Whether to use the min-height property"),
5897                           FALSE,
5898                           CLUTTER_PARAM_READWRITE);
5899
5900   /**
5901    * ClutterActor:natural-width-set:
5902    *
5903    * This flag controls whether the #ClutterActor:natural-width property
5904    * is used
5905    *
5906    * Since: 0.8
5907    */
5908   obj_props[PROP_NATURAL_WIDTH_SET] =
5909     g_param_spec_boolean ("natural-width-set",
5910                           P_("Natural width set"),
5911                           P_("Whether to use the natural-width property"),
5912                           FALSE,
5913                           CLUTTER_PARAM_READWRITE);
5914
5915   /**
5916    * ClutterActor:natural-height-set:
5917    *
5918    * This flag controls whether the #ClutterActor:natural-height property
5919    * is used
5920    *
5921    * Since: 0.8
5922    */
5923   obj_props[PROP_NATURAL_HEIGHT_SET] =
5924     g_param_spec_boolean ("natural-height-set",
5925                           P_("Natural height set"),
5926                           P_("Whether to use the natural-height property"),
5927                           FALSE,
5928                           CLUTTER_PARAM_READWRITE);
5929
5930   /**
5931    * ClutterActor:allocation:
5932    *
5933    * The allocation for the actor, in pixels
5934    *
5935    * This is property is read-only, but you might monitor it to know when an
5936    * actor moves or resizes
5937    *
5938    * Since: 0.8
5939    */
5940   obj_props[PROP_ALLOCATION] =
5941     g_param_spec_boxed ("allocation",
5942                         P_("Allocation"),
5943                         P_("The actor's allocation"),
5944                         CLUTTER_TYPE_ACTOR_BOX,
5945                         G_PARAM_READABLE |
5946                         G_PARAM_STATIC_STRINGS |
5947                         CLUTTER_PARAM_ANIMATABLE);
5948
5949   /**
5950    * ClutterActor:request-mode:
5951    *
5952    * Request mode for the #ClutterActor. The request mode determines the
5953    * type of geometry management used by the actor, either height for width
5954    * (the default) or width for height.
5955    *
5956    * For actors implementing height for width, the parent container should get
5957    * the preferred width first, and then the preferred height for that width.
5958    *
5959    * For actors implementing width for height, the parent container should get
5960    * the preferred height first, and then the preferred width for that height.
5961    *
5962    * For instance:
5963    *
5964    * |[
5965    *   ClutterRequestMode mode;
5966    *   gfloat natural_width, min_width;
5967    *   gfloat natural_height, min_height;
5968    *
5969    *   mode = clutter_actor_get_request_mode (child);
5970    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5971    *     {
5972    *       clutter_actor_get_preferred_width (child, -1,
5973    *                                          &amp;min_width,
5974    *                                          &amp;natural_width);
5975    *       clutter_actor_get_preferred_height (child, natural_width,
5976    *                                           &amp;min_height,
5977    *                                           &amp;natural_height);
5978    *     }
5979    *   else
5980    *     {
5981    *       clutter_actor_get_preferred_height (child, -1,
5982    *                                           &amp;min_height,
5983    *                                           &amp;natural_height);
5984    *       clutter_actor_get_preferred_width (child, natural_height,
5985    *                                          &amp;min_width,
5986    *                                          &amp;natural_width);
5987    *     }
5988    * ]|
5989    *
5990    * will retrieve the minimum and natural width and height depending on the
5991    * preferred request mode of the #ClutterActor "child".
5992    *
5993    * The clutter_actor_get_preferred_size() function will implement this
5994    * check for you.
5995    *
5996    * Since: 0.8
5997    */
5998   obj_props[PROP_REQUEST_MODE] =
5999     g_param_spec_enum ("request-mode",
6000                        P_("Request Mode"),
6001                        P_("The actor's request mode"),
6002                        CLUTTER_TYPE_REQUEST_MODE,
6003                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
6004                        CLUTTER_PARAM_READWRITE);
6005
6006   /**
6007    * ClutterActor:depth:
6008    *
6009    * The position of the actor on the Z axis.
6010    *
6011    * The #ClutterActor:depth property is relative to the parent's
6012    * modelview matrix.
6013    *
6014    * The #ClutterActor:depth property is animatable.
6015    *
6016    * Since: 0.6
6017    */
6018   obj_props[PROP_DEPTH] =
6019     g_param_spec_float ("depth",
6020                         P_("Depth"),
6021                         P_("Position on the Z axis"),
6022                         -G_MAXFLOAT, G_MAXFLOAT,
6023                         0.0,
6024                         G_PARAM_READWRITE |
6025                         G_PARAM_STATIC_STRINGS |
6026                         CLUTTER_PARAM_ANIMATABLE);
6027
6028   /**
6029    * ClutterActor:opacity:
6030    *
6031    * Opacity of an actor, between 0 (fully transparent) and
6032    * 255 (fully opaque)
6033    *
6034    * The #ClutterActor:opacity property is animatable.
6035    */
6036   obj_props[PROP_OPACITY] =
6037     g_param_spec_uint ("opacity",
6038                        P_("Opacity"),
6039                        P_("Opacity of an actor"),
6040                        0, 255,
6041                        255,
6042                        G_PARAM_READWRITE |
6043                        G_PARAM_STATIC_STRINGS |
6044                        CLUTTER_PARAM_ANIMATABLE);
6045
6046   /**
6047    * ClutterActor:offscreen-redirect:
6048    *
6049    * Determines the conditions in which the actor will be redirected
6050    * to an offscreen framebuffer while being painted. For example this
6051    * can be used to cache an actor in a framebuffer or for improved
6052    * handling of transparent actors. See
6053    * clutter_actor_set_offscreen_redirect() for details.
6054    *
6055    * Since: 1.8
6056    */
6057   obj_props[PROP_OFFSCREEN_REDIRECT] =
6058     g_param_spec_flags ("offscreen-redirect",
6059                         P_("Offscreen redirect"),
6060                         P_("Flags controlling when to flatten the actor into a single image"),
6061                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6062                         0,
6063                         CLUTTER_PARAM_READWRITE);
6064
6065   /**
6066    * ClutterActor:visible:
6067    *
6068    * Whether the actor is set to be visible or not
6069    *
6070    * See also #ClutterActor:mapped
6071    */
6072   obj_props[PROP_VISIBLE] =
6073     g_param_spec_boolean ("visible",
6074                           P_("Visible"),
6075                           P_("Whether the actor is visible or not"),
6076                           FALSE,
6077                           CLUTTER_PARAM_READWRITE);
6078
6079   /**
6080    * ClutterActor:mapped:
6081    *
6082    * Whether the actor is mapped (will be painted when the stage
6083    * to which it belongs is mapped)
6084    *
6085    * Since: 1.0
6086    */
6087   obj_props[PROP_MAPPED] =
6088     g_param_spec_boolean ("mapped",
6089                           P_("Mapped"),
6090                           P_("Whether the actor will be painted"),
6091                           FALSE,
6092                           CLUTTER_PARAM_READABLE);
6093
6094   /**
6095    * ClutterActor:realized:
6096    *
6097    * Whether the actor has been realized
6098    *
6099    * Since: 1.0
6100    */
6101   obj_props[PROP_REALIZED] =
6102     g_param_spec_boolean ("realized",
6103                           P_("Realized"),
6104                           P_("Whether the actor has been realized"),
6105                           FALSE,
6106                           CLUTTER_PARAM_READABLE);
6107
6108   /**
6109    * ClutterActor:reactive:
6110    *
6111    * Whether the actor is reactive to events or not
6112    *
6113    * Only reactive actors will emit event-related signals
6114    *
6115    * Since: 0.6
6116    */
6117   obj_props[PROP_REACTIVE] =
6118     g_param_spec_boolean ("reactive",
6119                           P_("Reactive"),
6120                           P_("Whether the actor is reactive to events"),
6121                           FALSE,
6122                           CLUTTER_PARAM_READWRITE);
6123
6124   /**
6125    * ClutterActor:has-clip:
6126    *
6127    * Whether the actor has the #ClutterActor:clip property set or not
6128    */
6129   obj_props[PROP_HAS_CLIP] =
6130     g_param_spec_boolean ("has-clip",
6131                           P_("Has Clip"),
6132                           P_("Whether the actor has a clip set"),
6133                           FALSE,
6134                           CLUTTER_PARAM_READABLE);
6135
6136   /**
6137    * ClutterActor:clip:
6138    *
6139    * The clip region for the actor, in actor-relative coordinates
6140    *
6141    * Every part of the actor outside the clip region will not be
6142    * painted
6143    */
6144   obj_props[PROP_CLIP] =
6145     g_param_spec_boxed ("clip",
6146                         P_("Clip"),
6147                         P_("The clip region for the actor"),
6148                         CLUTTER_TYPE_GEOMETRY,
6149                         CLUTTER_PARAM_READWRITE);
6150
6151   /**
6152    * ClutterActor:name:
6153    *
6154    * The name of the actor
6155    *
6156    * Since: 0.2
6157    */
6158   obj_props[PROP_NAME] =
6159     g_param_spec_string ("name",
6160                          P_("Name"),
6161                          P_("Name of the actor"),
6162                          NULL,
6163                          CLUTTER_PARAM_READWRITE);
6164
6165   /**
6166    * ClutterActor:scale-x:
6167    *
6168    * The horizontal scale of the actor.
6169    *
6170    * The #ClutterActor:scale-x property is animatable.
6171    *
6172    * Since: 0.6
6173    */
6174   obj_props[PROP_SCALE_X] =
6175     g_param_spec_double ("scale-x",
6176                          P_("Scale X"),
6177                          P_("Scale factor on the X axis"),
6178                          0.0, G_MAXDOUBLE,
6179                          1.0,
6180                          G_PARAM_READWRITE |
6181                          G_PARAM_STATIC_STRINGS |
6182                          CLUTTER_PARAM_ANIMATABLE);
6183
6184   /**
6185    * ClutterActor:scale-y:
6186    *
6187    * The vertical scale of the actor.
6188    *
6189    * The #ClutterActor:scale-y property is animatable.
6190    *
6191    * Since: 0.6
6192    */
6193   obj_props[PROP_SCALE_Y] =
6194     g_param_spec_double ("scale-y",
6195                          P_("Scale Y"),
6196                          P_("Scale factor on the Y axis"),
6197                          0.0, G_MAXDOUBLE,
6198                          1.0,
6199                          G_PARAM_READWRITE |
6200                          G_PARAM_STATIC_STRINGS |
6201                          CLUTTER_PARAM_ANIMATABLE);
6202
6203   /**
6204    * ClutterActor:scale-center-x:
6205    *
6206    * The horizontal center point for scaling
6207    *
6208    * Since: 1.0
6209    */
6210   obj_props[PROP_SCALE_CENTER_X] =
6211     g_param_spec_float ("scale-center-x",
6212                         P_("Scale Center X"),
6213                         P_("Horizontal scale center"),
6214                         -G_MAXFLOAT, G_MAXFLOAT,
6215                         0.0,
6216                         CLUTTER_PARAM_READWRITE);
6217
6218   /**
6219    * ClutterActor:scale-center-y:
6220    *
6221    * The vertical center point for scaling
6222    *
6223    * Since: 1.0
6224    */
6225   obj_props[PROP_SCALE_CENTER_Y] =
6226     g_param_spec_float ("scale-center-y",
6227                         P_("Scale Center Y"),
6228                         P_("Vertical scale center"),
6229                         -G_MAXFLOAT, G_MAXFLOAT,
6230                         0.0,
6231                         CLUTTER_PARAM_READWRITE);
6232
6233   /**
6234    * ClutterActor:scale-gravity:
6235    *
6236    * The center point for scaling expressed as a #ClutterGravity
6237    *
6238    * Since: 1.0
6239    */
6240   obj_props[PROP_SCALE_GRAVITY] =
6241     g_param_spec_enum ("scale-gravity",
6242                        P_("Scale Gravity"),
6243                        P_("The center of scaling"),
6244                        CLUTTER_TYPE_GRAVITY,
6245                        CLUTTER_GRAVITY_NONE,
6246                        CLUTTER_PARAM_READWRITE);
6247
6248   /**
6249    * ClutterActor:rotation-angle-x:
6250    *
6251    * The rotation angle on the X axis.
6252    *
6253    * The #ClutterActor:rotation-angle-x property is animatable.
6254    *
6255    * Since: 0.6
6256    */
6257   obj_props[PROP_ROTATION_ANGLE_X] =
6258     g_param_spec_double ("rotation-angle-x",
6259                          P_("Rotation Angle X"),
6260                          P_("The rotation angle on the X axis"),
6261                          -G_MAXDOUBLE, G_MAXDOUBLE,
6262                          0.0,
6263                          G_PARAM_READWRITE |
6264                          G_PARAM_STATIC_STRINGS |
6265                          CLUTTER_PARAM_ANIMATABLE);
6266
6267   /**
6268    * ClutterActor:rotation-angle-y:
6269    *
6270    * The rotation angle on the Y axis
6271    *
6272    * The #ClutterActor:rotation-angle-y property is animatable.
6273    *
6274    * Since: 0.6
6275    */
6276   obj_props[PROP_ROTATION_ANGLE_Y] =
6277     g_param_spec_double ("rotation-angle-y",
6278                          P_("Rotation Angle Y"),
6279                          P_("The rotation angle on the Y axis"),
6280                          -G_MAXDOUBLE, G_MAXDOUBLE,
6281                          0.0,
6282                          G_PARAM_READWRITE |
6283                          G_PARAM_STATIC_STRINGS |
6284                          CLUTTER_PARAM_ANIMATABLE);
6285
6286   /**
6287    * ClutterActor:rotation-angle-z:
6288    *
6289    * The rotation angle on the Z axis
6290    *
6291    * The #ClutterActor:rotation-angle-z property is animatable.
6292    *
6293    * Since: 0.6
6294    */
6295   obj_props[PROP_ROTATION_ANGLE_Z] =
6296     g_param_spec_double ("rotation-angle-z",
6297                          P_("Rotation Angle Z"),
6298                          P_("The rotation angle on the Z axis"),
6299                          -G_MAXDOUBLE, G_MAXDOUBLE,
6300                          0.0,
6301                          G_PARAM_READWRITE |
6302                          G_PARAM_STATIC_STRINGS |
6303                          CLUTTER_PARAM_ANIMATABLE);
6304
6305   /**
6306    * ClutterActor:rotation-center-x:
6307    *
6308    * The rotation center on the X axis.
6309    *
6310    * Since: 0.6
6311    */
6312   obj_props[PROP_ROTATION_CENTER_X] =
6313     g_param_spec_boxed ("rotation-center-x",
6314                         P_("Rotation Center X"),
6315                         P_("The rotation center on the X axis"),
6316                         CLUTTER_TYPE_VERTEX,
6317                         CLUTTER_PARAM_READWRITE);
6318
6319   /**
6320    * ClutterActor:rotation-center-y:
6321    *
6322    * The rotation center on the Y axis.
6323    *
6324    * Since: 0.6
6325    */
6326   obj_props[PROP_ROTATION_CENTER_Y] =
6327     g_param_spec_boxed ("rotation-center-y",
6328                         P_("Rotation Center Y"),
6329                         P_("The rotation center on the Y axis"),
6330                         CLUTTER_TYPE_VERTEX,
6331                         CLUTTER_PARAM_READWRITE);
6332
6333   /**
6334    * ClutterActor:rotation-center-z:
6335    *
6336    * The rotation center on the Z axis.
6337    *
6338    * Since: 0.6
6339    */
6340   obj_props[PROP_ROTATION_CENTER_Z] =
6341     g_param_spec_boxed ("rotation-center-z",
6342                         P_("Rotation Center Z"),
6343                         P_("The rotation center on the Z axis"),
6344                         CLUTTER_TYPE_VERTEX,
6345                         CLUTTER_PARAM_READWRITE);
6346
6347   /**
6348    * ClutterActor:rotation-center-z-gravity:
6349    *
6350    * The rotation center on the Z axis expressed as a #ClutterGravity.
6351    *
6352    * Since: 1.0
6353    */
6354   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6355     g_param_spec_enum ("rotation-center-z-gravity",
6356                        P_("Rotation Center Z Gravity"),
6357                        P_("Center point for rotation around the Z axis"),
6358                        CLUTTER_TYPE_GRAVITY,
6359                        CLUTTER_GRAVITY_NONE,
6360                        CLUTTER_PARAM_READWRITE);
6361
6362   /**
6363    * ClutterActor:anchor-x:
6364    *
6365    * The X coordinate of an actor's anchor point, relative to
6366    * the actor coordinate space, in pixels
6367    *
6368    * Since: 0.8
6369    */
6370   obj_props[PROP_ANCHOR_X] =
6371     g_param_spec_float ("anchor-x",
6372                         P_("Anchor X"),
6373                         P_("X coordinate of the anchor point"),
6374                         -G_MAXFLOAT, G_MAXFLOAT,
6375                         0,
6376                         CLUTTER_PARAM_READWRITE);
6377
6378   /**
6379    * ClutterActor:anchor-y:
6380    *
6381    * The Y coordinate of an actor's anchor point, relative to
6382    * the actor coordinate space, in pixels
6383    *
6384    * Since: 0.8
6385    */
6386   obj_props[PROP_ANCHOR_Y] =
6387     g_param_spec_float ("anchor-y",
6388                         P_("Anchor Y"),
6389                         P_("Y coordinate of the anchor point"),
6390                         -G_MAXFLOAT, G_MAXFLOAT,
6391                         0,
6392                         CLUTTER_PARAM_READWRITE);
6393
6394   /**
6395    * ClutterActor:anchor-gravity:
6396    *
6397    * The anchor point expressed as a #ClutterGravity
6398    *
6399    * Since: 1.0
6400    */
6401   obj_props[PROP_ANCHOR_GRAVITY] =
6402     g_param_spec_enum ("anchor-gravity",
6403                        P_("Anchor Gravity"),
6404                        P_("The anchor point as a ClutterGravity"),
6405                        CLUTTER_TYPE_GRAVITY,
6406                        CLUTTER_GRAVITY_NONE,
6407                        CLUTTER_PARAM_READWRITE);
6408
6409   /**
6410    * ClutterActor:show-on-set-parent:
6411    *
6412    * If %TRUE, the actor is automatically shown when parented.
6413    *
6414    * Calling clutter_actor_hide() on an actor which has not been
6415    * parented will set this property to %FALSE as a side effect.
6416    *
6417    * Since: 0.8
6418    */
6419   obj_props[PROP_SHOW_ON_SET_PARENT] =
6420     g_param_spec_boolean ("show-on-set-parent",
6421                           P_("Show on set parent"),
6422                           P_("Whether the actor is shown when parented"),
6423                           TRUE,
6424                           CLUTTER_PARAM_READWRITE);
6425
6426   /**
6427    * ClutterActor:clip-to-allocation:
6428    *
6429    * Whether the clip region should track the allocated area
6430    * of the actor.
6431    *
6432    * This property is ignored if a clip area has been explicitly
6433    * set using clutter_actor_set_clip().
6434    *
6435    * Since: 1.0
6436    */
6437   obj_props[PROP_CLIP_TO_ALLOCATION] =
6438     g_param_spec_boolean ("clip-to-allocation",
6439                           P_("Clip to Allocation"),
6440                           P_("Sets the clip region to track the actor's allocation"),
6441                           FALSE,
6442                           CLUTTER_PARAM_READWRITE);
6443
6444   /**
6445    * ClutterActor:text-direction:
6446    *
6447    * The direction of the text inside a #ClutterActor.
6448    *
6449    * Since: 1.0
6450    */
6451   obj_props[PROP_TEXT_DIRECTION] =
6452     g_param_spec_enum ("text-direction",
6453                        P_("Text Direction"),
6454                        P_("Direction of the text"),
6455                        CLUTTER_TYPE_TEXT_DIRECTION,
6456                        CLUTTER_TEXT_DIRECTION_LTR,
6457                        CLUTTER_PARAM_READWRITE);
6458
6459   /**
6460    * ClutterActor:has-pointer:
6461    *
6462    * Whether the actor contains the pointer of a #ClutterInputDevice
6463    * or not.
6464    *
6465    * Since: 1.2
6466    */
6467   obj_props[PROP_HAS_POINTER] =
6468     g_param_spec_boolean ("has-pointer",
6469                           P_("Has Pointer"),
6470                           P_("Whether the actor contains the pointer of an input device"),
6471                           FALSE,
6472                           CLUTTER_PARAM_READABLE);
6473
6474   /**
6475    * ClutterActor:actions:
6476    *
6477    * Adds a #ClutterAction to the actor
6478    *
6479    * Since: 1.4
6480    */
6481   obj_props[PROP_ACTIONS] =
6482     g_param_spec_object ("actions",
6483                          P_("Actions"),
6484                          P_("Adds an action to the actor"),
6485                          CLUTTER_TYPE_ACTION,
6486                          CLUTTER_PARAM_WRITABLE);
6487
6488   /**
6489    * ClutterActor:constraints:
6490    *
6491    * Adds a #ClutterConstraint to the actor
6492    *
6493    * Since: 1.4
6494    */
6495   obj_props[PROP_CONSTRAINTS] =
6496     g_param_spec_object ("constraints",
6497                          P_("Constraints"),
6498                          P_("Adds a constraint to the actor"),
6499                          CLUTTER_TYPE_CONSTRAINT,
6500                          CLUTTER_PARAM_WRITABLE);
6501
6502   /**
6503    * ClutterActor:effect:
6504    *
6505    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6506    *
6507    * Since: 1.4
6508    */
6509   obj_props[PROP_EFFECT] =
6510     g_param_spec_object ("effect",
6511                          P_("Effect"),
6512                          P_("Add an effect to be applied on the actor"),
6513                          CLUTTER_TYPE_EFFECT,
6514                          CLUTTER_PARAM_WRITABLE);
6515
6516   /**
6517    * ClutterActor:layout-manager:
6518    *
6519    * A delegate object for controlling the layout of the children of
6520    * an actor.
6521    *
6522    * Since: 1.10
6523    */
6524   obj_props[PROP_LAYOUT_MANAGER] =
6525     g_param_spec_object ("layout-manager",
6526                          P_("Layout Manager"),
6527                          P_("The object controlling the layout of an actor's children"),
6528                          CLUTTER_TYPE_LAYOUT_MANAGER,
6529                          CLUTTER_PARAM_READWRITE);
6530
6531   /**
6532    * ClutterActor:x-expand:
6533    *
6534    * Whether a layout manager should assign more space to the actor on
6535    * the X axis.
6536    *
6537    * Since: 1.12
6538    */
6539   obj_props[PROP_X_EXPAND] =
6540     g_param_spec_boolean ("x-expand",
6541                           P_("X Expand"),
6542                           P_("Whether extra horizontal space should be assigned to the actor"),
6543                           FALSE,
6544                           G_PARAM_READWRITE |
6545                           G_PARAM_STATIC_STRINGS);
6546
6547   /**
6548    * ClutterActor:y-expand:
6549    *
6550    * Whether a layout manager should assign more space to the actor on
6551    * the Y axis.
6552    *
6553    * Since: 1.12
6554    */
6555   obj_props[PROP_Y_EXPAND] =
6556     g_param_spec_boolean ("y-expand",
6557                           P_("Y Expand"),
6558                           P_("Whether extra vertical space should be assigned to the actor"),
6559                           FALSE,
6560                           G_PARAM_READWRITE |
6561                           G_PARAM_STATIC_STRINGS);
6562
6563   /**
6564    * ClutterActor:x-align:
6565    *
6566    * The alignment of an actor on the X axis, if the actor has been given
6567    * extra space for its allocation. See also the #ClutterActor:x-expand
6568    * property.
6569    *
6570    * Since: 1.10
6571    */
6572   obj_props[PROP_X_ALIGN] =
6573     g_param_spec_enum ("x-align",
6574                        P_("X Alignment"),
6575                        P_("The alignment of the actor on the X axis within its allocation"),
6576                        CLUTTER_TYPE_ACTOR_ALIGN,
6577                        CLUTTER_ACTOR_ALIGN_FILL,
6578                        CLUTTER_PARAM_READWRITE);
6579
6580   /**
6581    * ClutterActor:y-align:
6582    *
6583    * The alignment of an actor on the Y axis, if the actor has been given
6584    * extra space for its allocation.
6585    *
6586    * Since: 1.10
6587    */
6588   obj_props[PROP_Y_ALIGN] =
6589     g_param_spec_enum ("y-align",
6590                        P_("Y Alignment"),
6591                        P_("The alignment of the actor on the Y axis within its allocation"),
6592                        CLUTTER_TYPE_ACTOR_ALIGN,
6593                        CLUTTER_ACTOR_ALIGN_FILL,
6594                        CLUTTER_PARAM_READWRITE);
6595
6596   /**
6597    * ClutterActor:margin-top:
6598    *
6599    * The margin (in pixels) from the top of the actor.
6600    *
6601    * This property adds a margin to the actor's preferred size; the margin
6602    * will be automatically taken into account when allocating the actor.
6603    *
6604    * Since: 1.10
6605    */
6606   obj_props[PROP_MARGIN_TOP] =
6607     g_param_spec_float ("margin-top",
6608                         P_("Margin Top"),
6609                         P_("Extra space at the top"),
6610                         0.0, G_MAXFLOAT,
6611                         0.0,
6612                         CLUTTER_PARAM_READWRITE);
6613
6614   /**
6615    * ClutterActor:margin-bottom:
6616    *
6617    * The margin (in pixels) from the bottom of the actor.
6618    *
6619    * This property adds a margin to the actor's preferred size; the margin
6620    * will be automatically taken into account when allocating the actor.
6621    *
6622    * Since: 1.10
6623    */
6624   obj_props[PROP_MARGIN_BOTTOM] =
6625     g_param_spec_float ("margin-bottom",
6626                         P_("Margin Bottom"),
6627                         P_("Extra space at the bottom"),
6628                         0.0, G_MAXFLOAT,
6629                         0.0,
6630                         CLUTTER_PARAM_READWRITE);
6631
6632   /**
6633    * ClutterActor:margin-left:
6634    *
6635    * The margin (in pixels) from the left of the actor.
6636    *
6637    * This property adds a margin to the actor's preferred size; the margin
6638    * will be automatically taken into account when allocating the actor.
6639    *
6640    * Since: 1.10
6641    */
6642   obj_props[PROP_MARGIN_LEFT] =
6643     g_param_spec_float ("margin-left",
6644                         P_("Margin Left"),
6645                         P_("Extra space at the left"),
6646                         0.0, G_MAXFLOAT,
6647                         0.0,
6648                         CLUTTER_PARAM_READWRITE);
6649
6650   /**
6651    * ClutterActor:margin-right:
6652    *
6653    * The margin (in pixels) from the right of the actor.
6654    *
6655    * This property adds a margin to the actor's preferred size; the margin
6656    * will be automatically taken into account when allocating the actor.
6657    *
6658    * Since: 1.10
6659    */
6660   obj_props[PROP_MARGIN_RIGHT] =
6661     g_param_spec_float ("margin-right",
6662                         P_("Margin Right"),
6663                         P_("Extra space at the right"),
6664                         0.0, G_MAXFLOAT,
6665                         0.0,
6666                         CLUTTER_PARAM_READWRITE);
6667
6668   /**
6669    * ClutterActor:background-color-set:
6670    *
6671    * Whether the #ClutterActor:background-color property has been set.
6672    *
6673    * Since: 1.10
6674    */
6675   obj_props[PROP_BACKGROUND_COLOR_SET] =
6676     g_param_spec_boolean ("background-color-set",
6677                           P_("Background Color Set"),
6678                           P_("Whether the background color is set"),
6679                           FALSE,
6680                           CLUTTER_PARAM_READABLE);
6681
6682   /**
6683    * ClutterActor:background-color:
6684    *
6685    * Paints a solid fill of the actor's allocation using the specified
6686    * color.
6687    *
6688    * The #ClutterActor:background-color property is animatable.
6689    *
6690    * Since: 1.10
6691    */
6692   obj_props[PROP_BACKGROUND_COLOR] =
6693     clutter_param_spec_color ("background-color",
6694                               P_("Background color"),
6695                               P_("The actor's background color"),
6696                               CLUTTER_COLOR_Transparent,
6697                               G_PARAM_READWRITE |
6698                               G_PARAM_STATIC_STRINGS |
6699                               CLUTTER_PARAM_ANIMATABLE);
6700
6701   /**
6702    * ClutterActor:first-child:
6703    *
6704    * The actor's first child.
6705    *
6706    * Since: 1.10
6707    */
6708   obj_props[PROP_FIRST_CHILD] =
6709     g_param_spec_object ("first-child",
6710                          P_("First Child"),
6711                          P_("The actor's first child"),
6712                          CLUTTER_TYPE_ACTOR,
6713                          CLUTTER_PARAM_READABLE);
6714
6715   /**
6716    * ClutterActor:last-child:
6717    *
6718    * The actor's last child.
6719    *
6720    * Since: 1.10
6721    */
6722   obj_props[PROP_LAST_CHILD] =
6723     g_param_spec_object ("last-child",
6724                          P_("Last Child"),
6725                          P_("The actor's last child"),
6726                          CLUTTER_TYPE_ACTOR,
6727                          CLUTTER_PARAM_READABLE);
6728
6729   /**
6730    * ClutterActor:content:
6731    *
6732    * The #ClutterContent implementation that controls the content
6733    * of the actor.
6734    *
6735    * Since: 1.10
6736    */
6737   obj_props[PROP_CONTENT] =
6738     g_param_spec_object ("content",
6739                          P_("Content"),
6740                          P_("Delegate object for painting the actor's content"),
6741                          CLUTTER_TYPE_CONTENT,
6742                          CLUTTER_PARAM_READWRITE);
6743
6744   /**
6745    * ClutterActor:content-gravity:
6746    *
6747    * The alignment that should be honoured by the #ClutterContent
6748    * set with the #ClutterActor:content property.
6749    *
6750    * Changing the value of this property will change the bounding box of
6751    * the content; you can use the #ClutterActor:content-box property to
6752    * get the position and size of the content within the actor's
6753    * allocation.
6754    *
6755    * This property is meaningful only for #ClutterContent implementations
6756    * that have a preferred size, and if the preferred size is smaller than
6757    * the actor's allocation.
6758    *
6759    * The #ClutterActor:content-gravity property is animatable.
6760    *
6761    * Since: 1.10
6762    */
6763   obj_props[PROP_CONTENT_GRAVITY] =
6764     g_param_spec_enum ("content-gravity",
6765                        P_("Content Gravity"),
6766                        P_("Alignment of the actor's content"),
6767                        CLUTTER_TYPE_CONTENT_GRAVITY,
6768                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6769                        CLUTTER_PARAM_READWRITE);
6770
6771   /**
6772    * ClutterActor:content-box:
6773    *
6774    * The bounding box for the #ClutterContent used by the actor.
6775    *
6776    * The value of this property is controlled by the #ClutterActor:allocation
6777    * and #ClutterActor:content-gravity properties of #ClutterActor.
6778    *
6779    * The bounding box for the content is guaranteed to never exceed the
6780    * allocation's of the actor.
6781    *
6782    * Since: 1.10
6783    */
6784   obj_props[PROP_CONTENT_BOX] =
6785     g_param_spec_boxed ("content-box",
6786                         P_("Content Box"),
6787                         P_("The bounding box of the actor's content"),
6788                         CLUTTER_TYPE_ACTOR_BOX,
6789                         G_PARAM_READABLE |
6790                         G_PARAM_STATIC_STRINGS |
6791                         CLUTTER_PARAM_ANIMATABLE);
6792
6793   obj_props[PROP_MINIFICATION_FILTER] =
6794     g_param_spec_enum ("minification-filter",
6795                        P_("Minification Filter"),
6796                        P_("The filter used when reducing the size of the content"),
6797                        CLUTTER_TYPE_SCALING_FILTER,
6798                        CLUTTER_SCALING_FILTER_LINEAR,
6799                        CLUTTER_PARAM_READWRITE);
6800
6801   obj_props[PROP_MAGNIFICATION_FILTER] =
6802     g_param_spec_enum ("magnification-filter",
6803                        P_("Magnification Filter"),
6804                        P_("The filter used when increasing the size of the content"),
6805                        CLUTTER_TYPE_SCALING_FILTER,
6806                        CLUTTER_SCALING_FILTER_LINEAR,
6807                        CLUTTER_PARAM_READWRITE);
6808
6809   /**
6810    * ClutterActor:content-repeat:
6811    *
6812    * The repeat policy for the actor's #ClutterActor:content.
6813    *
6814    * Since: 1.12
6815    */
6816   obj_props[PROP_CONTENT_REPEAT] =
6817     g_param_spec_flags ("content-repeat",
6818                         P_("Content Repeat"),
6819                         P_("The repeat policy for the actor's content"),
6820                         CLUTTER_TYPE_CONTENT_REPEAT,
6821                         CLUTTER_REPEAT_NONE,
6822                         G_PARAM_READWRITE |
6823                         G_PARAM_STATIC_STRINGS);
6824
6825   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6826
6827   /**
6828    * ClutterActor::destroy:
6829    * @actor: the #ClutterActor which emitted the signal
6830    *
6831    * The ::destroy signal notifies that all references held on the
6832    * actor which emitted it should be released.
6833    *
6834    * The ::destroy signal should be used by all holders of a reference
6835    * on @actor.
6836    *
6837    * This signal might result in the finalization of the #ClutterActor
6838    * if all references are released.
6839    *
6840    * Composite actors and actors implementing the #ClutterContainer
6841    * interface should override the default implementation of the
6842    * class handler of this signal and call clutter_actor_destroy() on
6843    * their children. When overriding the default class handler, it is
6844    * required to chain up to the parent's implementation.
6845    *
6846    * Since: 0.2
6847    */
6848   actor_signals[DESTROY] =
6849     g_signal_new (I_("destroy"),
6850                   G_TYPE_FROM_CLASS (object_class),
6851                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6852                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6853                   NULL, NULL,
6854                   _clutter_marshal_VOID__VOID,
6855                   G_TYPE_NONE, 0);
6856   /**
6857    * ClutterActor::show:
6858    * @actor: the object which received the signal
6859    *
6860    * The ::show signal is emitted when an actor is visible and
6861    * rendered on the stage.
6862    *
6863    * Since: 0.2
6864    */
6865   actor_signals[SHOW] =
6866     g_signal_new (I_("show"),
6867                   G_TYPE_FROM_CLASS (object_class),
6868                   G_SIGNAL_RUN_FIRST,
6869                   G_STRUCT_OFFSET (ClutterActorClass, show),
6870                   NULL, NULL,
6871                   _clutter_marshal_VOID__VOID,
6872                   G_TYPE_NONE, 0);
6873   /**
6874    * ClutterActor::hide:
6875    * @actor: the object which received the signal
6876    *
6877    * The ::hide signal is emitted when an actor is no longer rendered
6878    * on the stage.
6879    *
6880    * Since: 0.2
6881    */
6882   actor_signals[HIDE] =
6883     g_signal_new (I_("hide"),
6884                   G_TYPE_FROM_CLASS (object_class),
6885                   G_SIGNAL_RUN_FIRST,
6886                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6887                   NULL, NULL,
6888                   _clutter_marshal_VOID__VOID,
6889                   G_TYPE_NONE, 0);
6890   /**
6891    * ClutterActor::parent-set:
6892    * @actor: the object which received the signal
6893    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6894    *
6895    * This signal is emitted when the parent of the actor changes.
6896    *
6897    * Since: 0.2
6898    */
6899   actor_signals[PARENT_SET] =
6900     g_signal_new (I_("parent-set"),
6901                   G_TYPE_FROM_CLASS (object_class),
6902                   G_SIGNAL_RUN_LAST,
6903                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6904                   NULL, NULL,
6905                   _clutter_marshal_VOID__OBJECT,
6906                   G_TYPE_NONE, 1,
6907                   CLUTTER_TYPE_ACTOR);
6908
6909   /**
6910    * ClutterActor::queue-redraw:
6911    * @actor: the actor we're bubbling the redraw request through
6912    * @origin: the actor which initiated the redraw request
6913    *
6914    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6915    * is called on @origin.
6916    *
6917    * The default implementation for #ClutterActor chains up to the
6918    * parent actor and queues a redraw on the parent, thus "bubbling"
6919    * the redraw queue up through the actor graph. The default
6920    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6921    * in a main loop idle handler.
6922    *
6923    * Note that the @origin actor may be the stage, or a container; it
6924    * does not have to be a leaf node in the actor graph.
6925    *
6926    * Toolkits embedding a #ClutterStage which require a redraw and
6927    * relayout cycle can stop the emission of this signal using the
6928    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6929    * themselves, like:
6930    *
6931    * |[
6932    *   static void
6933    *   on_redraw_complete (gpointer data)
6934    *   {
6935    *     ClutterStage *stage = data;
6936    *
6937    *     /&ast; execute the Clutter drawing pipeline &ast;/
6938    *     clutter_stage_ensure_redraw (stage);
6939    *   }
6940    *
6941    *   static void
6942    *   on_stage_queue_redraw (ClutterStage *stage)
6943    *   {
6944    *     /&ast; this prevents the default handler to run &ast;/
6945    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6946    *
6947    *     /&ast; queue a redraw with the host toolkit and call
6948    *      &ast; a function when the redraw has been completed
6949    *      &ast;/
6950    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6951    *   }
6952    * ]|
6953    *
6954    * <note><para>This signal is emitted before the Clutter paint
6955    * pipeline is executed. If you want to know when the pipeline has
6956    * been completed you should connect to the ::paint signal on the
6957    * Stage with g_signal_connect_after().</para></note>
6958    *
6959    * Since: 1.0
6960    */
6961   actor_signals[QUEUE_REDRAW] =
6962     g_signal_new (I_("queue-redraw"),
6963                   G_TYPE_FROM_CLASS (object_class),
6964                   G_SIGNAL_RUN_LAST |
6965                   G_SIGNAL_NO_HOOKS,
6966                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6967                   NULL, NULL,
6968                   _clutter_marshal_VOID__OBJECT,
6969                   G_TYPE_NONE, 1,
6970                   CLUTTER_TYPE_ACTOR);
6971
6972   /**
6973    * ClutterActor::queue-relayout:
6974    * @actor: the actor being queued for relayout
6975    *
6976    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6977    * is called on an actor.
6978    *
6979    * The default implementation for #ClutterActor chains up to the
6980    * parent actor and queues a relayout on the parent, thus "bubbling"
6981    * the relayout queue up through the actor graph.
6982    *
6983    * The main purpose of this signal is to allow relayout to be propagated
6984    * properly in the procense of #ClutterClone actors. Applications will
6985    * not normally need to connect to this signal.
6986    *
6987    * Since: 1.2
6988    */
6989   actor_signals[QUEUE_RELAYOUT] =
6990     g_signal_new (I_("queue-relayout"),
6991                   G_TYPE_FROM_CLASS (object_class),
6992                   G_SIGNAL_RUN_LAST |
6993                   G_SIGNAL_NO_HOOKS,
6994                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6995                   NULL, NULL,
6996                   _clutter_marshal_VOID__VOID,
6997                   G_TYPE_NONE, 0);
6998
6999   /**
7000    * ClutterActor::event:
7001    * @actor: the actor which received the event
7002    * @event: a #ClutterEvent
7003    *
7004    * The ::event signal is emitted each time an event is received
7005    * by the @actor. This signal will be emitted on every actor,
7006    * following the hierarchy chain, until it reaches the top-level
7007    * container (the #ClutterStage).
7008    *
7009    * Return value: %TRUE if the event has been handled by the actor,
7010    *   or %FALSE to continue the emission.
7011    *
7012    * Since: 0.6
7013    */
7014   actor_signals[EVENT] =
7015     g_signal_new (I_("event"),
7016                   G_TYPE_FROM_CLASS (object_class),
7017                   G_SIGNAL_RUN_LAST,
7018                   G_STRUCT_OFFSET (ClutterActorClass, event),
7019                   _clutter_boolean_handled_accumulator, NULL,
7020                   _clutter_marshal_BOOLEAN__BOXED,
7021                   G_TYPE_BOOLEAN, 1,
7022                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7023   /**
7024    * ClutterActor::button-press-event:
7025    * @actor: the actor which received the event
7026    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7027    *
7028    * The ::button-press-event signal is emitted each time a mouse button
7029    * is pressed on @actor.
7030    *
7031    * Return value: %TRUE if the event has been handled by the actor,
7032    *   or %FALSE to continue the emission.
7033    *
7034    * Since: 0.6
7035    */
7036   actor_signals[BUTTON_PRESS_EVENT] =
7037     g_signal_new (I_("button-press-event"),
7038                   G_TYPE_FROM_CLASS (object_class),
7039                   G_SIGNAL_RUN_LAST,
7040                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7041                   _clutter_boolean_handled_accumulator, NULL,
7042                   _clutter_marshal_BOOLEAN__BOXED,
7043                   G_TYPE_BOOLEAN, 1,
7044                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7045   /**
7046    * ClutterActor::button-release-event:
7047    * @actor: the actor which received the event
7048    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7049    *
7050    * The ::button-release-event signal is emitted each time a mouse button
7051    * is released on @actor.
7052    *
7053    * Return value: %TRUE if the event has been handled by the actor,
7054    *   or %FALSE to continue the emission.
7055    *
7056    * Since: 0.6
7057    */
7058   actor_signals[BUTTON_RELEASE_EVENT] =
7059     g_signal_new (I_("button-release-event"),
7060                   G_TYPE_FROM_CLASS (object_class),
7061                   G_SIGNAL_RUN_LAST,
7062                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7063                   _clutter_boolean_handled_accumulator, NULL,
7064                   _clutter_marshal_BOOLEAN__BOXED,
7065                   G_TYPE_BOOLEAN, 1,
7066                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7067   /**
7068    * ClutterActor::scroll-event:
7069    * @actor: the actor which received the event
7070    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7071    *
7072    * The ::scroll-event signal is emitted each time the mouse is
7073    * scrolled on @actor
7074    *
7075    * Return value: %TRUE if the event has been handled by the actor,
7076    *   or %FALSE to continue the emission.
7077    *
7078    * Since: 0.6
7079    */
7080   actor_signals[SCROLL_EVENT] =
7081     g_signal_new (I_("scroll-event"),
7082                   G_TYPE_FROM_CLASS (object_class),
7083                   G_SIGNAL_RUN_LAST,
7084                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7085                   _clutter_boolean_handled_accumulator, NULL,
7086                   _clutter_marshal_BOOLEAN__BOXED,
7087                   G_TYPE_BOOLEAN, 1,
7088                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7089   /**
7090    * ClutterActor::key-press-event:
7091    * @actor: the actor which received the event
7092    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7093    *
7094    * The ::key-press-event signal is emitted each time a keyboard button
7095    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7096    *
7097    * Return value: %TRUE if the event has been handled by the actor,
7098    *   or %FALSE to continue the emission.
7099    *
7100    * Since: 0.6
7101    */
7102   actor_signals[KEY_PRESS_EVENT] =
7103     g_signal_new (I_("key-press-event"),
7104                   G_TYPE_FROM_CLASS (object_class),
7105                   G_SIGNAL_RUN_LAST,
7106                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7107                   _clutter_boolean_handled_accumulator, NULL,
7108                   _clutter_marshal_BOOLEAN__BOXED,
7109                   G_TYPE_BOOLEAN, 1,
7110                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7111   /**
7112    * ClutterActor::key-release-event:
7113    * @actor: the actor which received the event
7114    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7115    *
7116    * The ::key-release-event signal is emitted each time a keyboard button
7117    * is released while @actor has key focus (see
7118    * clutter_stage_set_key_focus()).
7119    *
7120    * Return value: %TRUE if the event has been handled by the actor,
7121    *   or %FALSE to continue the emission.
7122    *
7123    * Since: 0.6
7124    */
7125   actor_signals[KEY_RELEASE_EVENT] =
7126     g_signal_new (I_("key-release-event"),
7127                   G_TYPE_FROM_CLASS (object_class),
7128                   G_SIGNAL_RUN_LAST,
7129                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7130                   _clutter_boolean_handled_accumulator, NULL,
7131                   _clutter_marshal_BOOLEAN__BOXED,
7132                   G_TYPE_BOOLEAN, 1,
7133                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7134   /**
7135    * ClutterActor::motion-event:
7136    * @actor: the actor which received the event
7137    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7138    *
7139    * The ::motion-event signal is emitted each time the mouse pointer is
7140    * moved over @actor.
7141    *
7142    * Return value: %TRUE if the event has been handled by the actor,
7143    *   or %FALSE to continue the emission.
7144    *
7145    * Since: 0.6
7146    */
7147   actor_signals[MOTION_EVENT] =
7148     g_signal_new (I_("motion-event"),
7149                   G_TYPE_FROM_CLASS (object_class),
7150                   G_SIGNAL_RUN_LAST,
7151                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7152                   _clutter_boolean_handled_accumulator, NULL,
7153                   _clutter_marshal_BOOLEAN__BOXED,
7154                   G_TYPE_BOOLEAN, 1,
7155                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7156
7157   /**
7158    * ClutterActor::key-focus-in:
7159    * @actor: the actor which now has key focus
7160    *
7161    * The ::key-focus-in signal is emitted when @actor receives key focus.
7162    *
7163    * Since: 0.6
7164    */
7165   actor_signals[KEY_FOCUS_IN] =
7166     g_signal_new (I_("key-focus-in"),
7167                   G_TYPE_FROM_CLASS (object_class),
7168                   G_SIGNAL_RUN_LAST,
7169                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7170                   NULL, NULL,
7171                   _clutter_marshal_VOID__VOID,
7172                   G_TYPE_NONE, 0);
7173
7174   /**
7175    * ClutterActor::key-focus-out:
7176    * @actor: the actor which now has key focus
7177    *
7178    * The ::key-focus-out signal is emitted when @actor loses key focus.
7179    *
7180    * Since: 0.6
7181    */
7182   actor_signals[KEY_FOCUS_OUT] =
7183     g_signal_new (I_("key-focus-out"),
7184                   G_TYPE_FROM_CLASS (object_class),
7185                   G_SIGNAL_RUN_LAST,
7186                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7187                   NULL, NULL,
7188                   _clutter_marshal_VOID__VOID,
7189                   G_TYPE_NONE, 0);
7190
7191   /**
7192    * ClutterActor::enter-event:
7193    * @actor: the actor which the pointer has entered.
7194    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7195    *
7196    * The ::enter-event signal is emitted when the pointer enters the @actor
7197    *
7198    * Return value: %TRUE if the event has been handled by the actor,
7199    *   or %FALSE to continue the emission.
7200    *
7201    * Since: 0.6
7202    */
7203   actor_signals[ENTER_EVENT] =
7204     g_signal_new (I_("enter-event"),
7205                   G_TYPE_FROM_CLASS (object_class),
7206                   G_SIGNAL_RUN_LAST,
7207                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7208                   _clutter_boolean_handled_accumulator, NULL,
7209                   _clutter_marshal_BOOLEAN__BOXED,
7210                   G_TYPE_BOOLEAN, 1,
7211                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7212
7213   /**
7214    * ClutterActor::leave-event:
7215    * @actor: the actor which the pointer has left
7216    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7217    *
7218    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7219    *
7220    * Return value: %TRUE if the event has been handled by the actor,
7221    *   or %FALSE to continue the emission.
7222    *
7223    * Since: 0.6
7224    */
7225   actor_signals[LEAVE_EVENT] =
7226     g_signal_new (I_("leave-event"),
7227                   G_TYPE_FROM_CLASS (object_class),
7228                   G_SIGNAL_RUN_LAST,
7229                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7230                   _clutter_boolean_handled_accumulator, NULL,
7231                   _clutter_marshal_BOOLEAN__BOXED,
7232                   G_TYPE_BOOLEAN, 1,
7233                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7234
7235   /**
7236    * ClutterActor::captured-event:
7237    * @actor: the actor which received the signal
7238    * @event: a #ClutterEvent
7239    *
7240    * The ::captured-event signal is emitted when an event is captured
7241    * by Clutter. This signal will be emitted starting from the top-level
7242    * container (the #ClutterStage) to the actor which received the event
7243    * going down the hierarchy. This signal can be used to intercept every
7244    * event before the specialized events (like
7245    * ClutterActor::button-press-event or ::key-released-event) are
7246    * emitted.
7247    *
7248    * Return value: %TRUE if the event has been handled by the actor,
7249    *   or %FALSE to continue the emission.
7250    *
7251    * Since: 0.6
7252    */
7253   actor_signals[CAPTURED_EVENT] =
7254     g_signal_new (I_("captured-event"),
7255                   G_TYPE_FROM_CLASS (object_class),
7256                   G_SIGNAL_RUN_LAST,
7257                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7258                   _clutter_boolean_handled_accumulator, NULL,
7259                   _clutter_marshal_BOOLEAN__BOXED,
7260                   G_TYPE_BOOLEAN, 1,
7261                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7262
7263   /**
7264    * ClutterActor::paint:
7265    * @actor: the #ClutterActor that received the signal
7266    *
7267    * The ::paint signal is emitted each time an actor is being painted.
7268    *
7269    * Subclasses of #ClutterActor should override the class signal handler
7270    * and paint themselves in that function.
7271    *
7272    * It is possible to connect a handler to the ::paint signal in order
7273    * to set up some custom aspect of a paint.
7274    *
7275    * Since: 0.8
7276    */
7277   actor_signals[PAINT] =
7278     g_signal_new (I_("paint"),
7279                   G_TYPE_FROM_CLASS (object_class),
7280                   G_SIGNAL_RUN_LAST |
7281                   G_SIGNAL_NO_HOOKS,
7282                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7283                   NULL, NULL,
7284                   _clutter_marshal_VOID__VOID,
7285                   G_TYPE_NONE, 0);
7286   /**
7287    * ClutterActor::realize:
7288    * @actor: the #ClutterActor that received the signal
7289    *
7290    * The ::realize signal is emitted each time an actor is being
7291    * realized.
7292    *
7293    * Since: 0.8
7294    */
7295   actor_signals[REALIZE] =
7296     g_signal_new (I_("realize"),
7297                   G_TYPE_FROM_CLASS (object_class),
7298                   G_SIGNAL_RUN_LAST,
7299                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7300                   NULL, NULL,
7301                   _clutter_marshal_VOID__VOID,
7302                   G_TYPE_NONE, 0);
7303   /**
7304    * ClutterActor::unrealize:
7305    * @actor: the #ClutterActor that received the signal
7306    *
7307    * The ::unrealize signal is emitted each time an actor is being
7308    * unrealized.
7309    *
7310    * Since: 0.8
7311    */
7312   actor_signals[UNREALIZE] =
7313     g_signal_new (I_("unrealize"),
7314                   G_TYPE_FROM_CLASS (object_class),
7315                   G_SIGNAL_RUN_LAST,
7316                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7317                   NULL, NULL,
7318                   _clutter_marshal_VOID__VOID,
7319                   G_TYPE_NONE, 0);
7320
7321   /**
7322    * ClutterActor::pick:
7323    * @actor: the #ClutterActor that received the signal
7324    * @color: the #ClutterColor to be used when picking
7325    *
7326    * The ::pick signal is emitted each time an actor is being painted
7327    * in "pick mode". The pick mode is used to identify the actor during
7328    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7329    * The actor should paint its shape using the passed @pick_color.
7330    *
7331    * Subclasses of #ClutterActor should override the class signal handler
7332    * and paint themselves in that function.
7333    *
7334    * It is possible to connect a handler to the ::pick signal in order
7335    * to set up some custom aspect of a paint in pick mode.
7336    *
7337    * Since: 1.0
7338    */
7339   actor_signals[PICK] =
7340     g_signal_new (I_("pick"),
7341                   G_TYPE_FROM_CLASS (object_class),
7342                   G_SIGNAL_RUN_LAST,
7343                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7344                   NULL, NULL,
7345                   _clutter_marshal_VOID__BOXED,
7346                   G_TYPE_NONE, 1,
7347                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7348
7349   /**
7350    * ClutterActor::allocation-changed:
7351    * @actor: the #ClutterActor that emitted the signal
7352    * @box: a #ClutterActorBox with the new allocation
7353    * @flags: #ClutterAllocationFlags for the allocation
7354    *
7355    * The ::allocation-changed signal is emitted when the
7356    * #ClutterActor:allocation property changes. Usually, application
7357    * code should just use the notifications for the :allocation property
7358    * but if you want to track the allocation flags as well, for instance
7359    * to know whether the absolute origin of @actor changed, then you might
7360    * want use this signal instead.
7361    *
7362    * Since: 1.0
7363    */
7364   actor_signals[ALLOCATION_CHANGED] =
7365     g_signal_new (I_("allocation-changed"),
7366                   G_TYPE_FROM_CLASS (object_class),
7367                   G_SIGNAL_RUN_LAST,
7368                   0,
7369                   NULL, NULL,
7370                   _clutter_marshal_VOID__BOXED_FLAGS,
7371                   G_TYPE_NONE, 2,
7372                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7373                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7374
7375   /**
7376    * ClutterActor::transitions-completed:
7377    * @actor: a #ClutterActor
7378    *
7379    * The ::transitions-completed signal is emitted once all transitions
7380    * involving @actor are complete.
7381    *
7382    * Since: 1.10
7383    */
7384   actor_signals[TRANSITIONS_COMPLETED] =
7385     g_signal_new (I_("transitions-completed"),
7386                   G_TYPE_FROM_CLASS (object_class),
7387                   G_SIGNAL_RUN_LAST,
7388                   0,
7389                   NULL, NULL,
7390                   _clutter_marshal_VOID__VOID,
7391                   G_TYPE_NONE, 0);
7392 }
7393
7394 static void
7395 clutter_actor_init (ClutterActor *self)
7396 {
7397   ClutterActorPrivate *priv;
7398
7399   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7400
7401   priv->id = _clutter_context_acquire_id (self);
7402   priv->pick_id = -1;
7403
7404   priv->opacity = 0xff;
7405   priv->show_on_set_parent = TRUE;
7406
7407   priv->needs_width_request = TRUE;
7408   priv->needs_height_request = TRUE;
7409   priv->needs_allocation = TRUE;
7410
7411   priv->cached_width_age = 1;
7412   priv->cached_height_age = 1;
7413
7414   priv->opacity_override = -1;
7415   priv->enable_model_view_transform = TRUE;
7416
7417   /* Initialize an empty paint volume to start with */
7418   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7419   priv->last_paint_volume_valid = TRUE;
7420
7421   priv->transform_valid = FALSE;
7422
7423   /* the default is to stretch the content, to match the
7424    * current behaviour of basically all actors. also, it's
7425    * the easiest thing to compute.
7426    */
7427   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7428   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7429   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7430
7431   /* this flag will be set to TRUE if the actor gets a child
7432    * or if the [xy]-expand flags are explicitly set; until
7433    * then, the actor does not need to expand.
7434    *
7435    * this also allows us to avoid computing the expand flag
7436    * when building up a scene.
7437    */
7438   priv->needs_compute_expand = FALSE;
7439
7440   clutter_actor_save_easing_state (self);
7441   clutter_actor_set_easing_duration (self, 0);
7442 }
7443
7444 /**
7445  * clutter_actor_new:
7446  *
7447  * Creates a new #ClutterActor.
7448  *
7449  * A newly created actor has a floating reference, which will be sunk
7450  * when it is added to another actor.
7451  *
7452  * Return value: (transfer full): the newly created #ClutterActor
7453  *
7454  * Since: 1.10
7455  */
7456 ClutterActor *
7457 clutter_actor_new (void)
7458 {
7459   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7460 }
7461
7462 /**
7463  * clutter_actor_destroy:
7464  * @self: a #ClutterActor
7465  *
7466  * Destroys an actor.  When an actor is destroyed, it will break any
7467  * references it holds to other objects.  If the actor is inside a
7468  * container, the actor will be removed.
7469  *
7470  * When you destroy a container, its children will be destroyed as well.
7471  *
7472  * Note: you cannot destroy the #ClutterStage returned by
7473  * clutter_stage_get_default().
7474  */
7475 void
7476 clutter_actor_destroy (ClutterActor *self)
7477 {
7478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7479
7480   g_object_ref (self);
7481
7482   /* avoid recursion while destroying */
7483   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7484     {
7485       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7486
7487       g_object_run_dispose (G_OBJECT (self));
7488
7489       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7490     }
7491
7492   g_object_unref (self);
7493 }
7494
7495 void
7496 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7497                                     ClutterPaintVolume *clip)
7498 {
7499   ClutterActorPrivate *priv = self->priv;
7500   ClutterPaintVolume *pv;
7501   gboolean clipped;
7502
7503   /* Remove queue entry early in the process, otherwise a new
7504      queue_redraw() during signal handling could put back this
7505      object in the stage redraw list (but the entry is freed as
7506      soon as we return from this function, causing a segfault
7507      later)
7508   */
7509   priv->queue_redraw_entry = NULL;
7510
7511   /* If we've been explicitly passed a clip volume then there's
7512    * nothing more to calculate, but otherwise the only thing we know
7513    * is that the change is constrained to the given actor.
7514    *
7515    * The idea is that if we know the paint volume for where the actor
7516    * was last drawn (in eye coordinates) and we also have the paint
7517    * volume for where it will be drawn next (in actor coordinates)
7518    * then if we queue a redraw for both these volumes that will cover
7519    * everything that needs to be redrawn to clear the old view and
7520    * show the latest view of the actor.
7521    *
7522    * Don't clip this redraw if we don't know what position we had for
7523    * the previous redraw since we don't know where to set the clip so
7524    * it will clear the actor as it is currently.
7525    */
7526   if (clip)
7527     {
7528       _clutter_actor_set_queue_redraw_clip (self, clip);
7529       clipped = TRUE;
7530     }
7531   else if (G_LIKELY (priv->last_paint_volume_valid))
7532     {
7533       pv = _clutter_actor_get_paint_volume_mutable (self);
7534       if (pv)
7535         {
7536           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7537
7538           /* make sure we redraw the actors old position... */
7539           _clutter_actor_set_queue_redraw_clip (stage,
7540                                                 &priv->last_paint_volume);
7541           _clutter_actor_signal_queue_redraw (stage, stage);
7542           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7543
7544           /* XXX: Ideally the redraw signal would take a clip volume
7545            * argument, but that would be an ABI break. Until we can
7546            * break the ABI we pass the argument out-of-band
7547            */
7548
7549           /* setup the clip for the actors new position... */
7550           _clutter_actor_set_queue_redraw_clip (self, pv);
7551           clipped = TRUE;
7552         }
7553       else
7554         clipped = FALSE;
7555     }
7556   else
7557     clipped = FALSE;
7558
7559   _clutter_actor_signal_queue_redraw (self, self);
7560
7561   /* Just in case anyone is manually firing redraw signals without
7562    * using the public queue_redraw() API we are careful to ensure that
7563    * our out-of-band clip member is cleared before returning...
7564    *
7565    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7566    */
7567   if (G_LIKELY (clipped))
7568     _clutter_actor_set_queue_redraw_clip (self, NULL);
7569 }
7570
7571 static void
7572 _clutter_actor_get_allocation_clip (ClutterActor *self,
7573                                     ClutterActorBox *clip)
7574 {
7575   ClutterActorBox allocation;
7576
7577   /* XXX: we don't care if we get an out of date allocation here
7578    * because clutter_actor_queue_redraw_with_clip knows to ignore
7579    * the clip if the actor's allocation is invalid.
7580    *
7581    * This is noted because clutter_actor_get_allocation_box does some
7582    * unnecessary work to support buggy code with a comment suggesting
7583    * that it could be changed later which would be good for this use
7584    * case!
7585    */
7586   clutter_actor_get_allocation_box (self, &allocation);
7587
7588   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7589    * actor's own coordinate space but the allocation is in parent
7590    * coordinates */
7591   clip->x1 = 0;
7592   clip->y1 = 0;
7593   clip->x2 = allocation.x2 - allocation.x1;
7594   clip->y2 = allocation.y2 - allocation.y1;
7595 }
7596
7597 void
7598 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7599                                   ClutterRedrawFlags  flags,
7600                                   ClutterPaintVolume *volume,
7601                                   ClutterEffect      *effect)
7602 {
7603   ClutterActorPrivate *priv = self->priv;
7604   ClutterPaintVolume allocation_pv;
7605   ClutterPaintVolume *pv;
7606   gboolean should_free_pv;
7607   ClutterActor *stage;
7608
7609   /* Here's an outline of the actor queue redraw mechanism:
7610    *
7611    * The process starts in one of the following two functions which
7612    * are wrappers for this function:
7613    * clutter_actor_queue_redraw
7614    * _clutter_actor_queue_redraw_with_clip
7615    *
7616    * additionally, an effect can queue a redraw by wrapping this
7617    * function in clutter_effect_queue_rerun
7618    *
7619    * This functions queues an entry in a list associated with the
7620    * stage which is a list of actors that queued a redraw while
7621    * updating the timelines, performing layouting and processing other
7622    * mainloop sources before the next paint starts.
7623    *
7624    * We aim to minimize the processing done at this point because
7625    * there is a good chance other events will happen while updating
7626    * the scenegraph that would invalidate any expensive work we might
7627    * otherwise try to do here. For example we don't try and resolve
7628    * the screen space bounding box of an actor at this stage so as to
7629    * minimize how much of the screen redraw because it's possible
7630    * something else will happen which will force a full redraw anyway.
7631    *
7632    * When all updates are complete and we come to paint the stage then
7633    * we iterate this list and actually emit the "queue-redraw" signals
7634    * for each of the listed actors which will bubble up to the stage
7635    * for each actor and at that point we will transform the actors
7636    * paint volume into screen coordinates to determine the clip region
7637    * for what needs to be redrawn in the next paint.
7638    *
7639    * Besides minimizing redundant work another reason for this
7640    * deferred design is that it's more likely we will be able to
7641    * determine the paint volume of an actor once we've finished
7642    * updating the scenegraph because its allocation should be up to
7643    * date. NB: If we can't determine an actors paint volume then we
7644    * can't automatically queue a clipped redraw which can make a big
7645    * difference to performance.
7646    *
7647    * So the control flow goes like this:
7648    * One of clutter_actor_queue_redraw,
7649    *        _clutter_actor_queue_redraw_with_clip
7650    *     or clutter_effect_queue_rerun
7651    *
7652    * then control moves to:
7653    *   _clutter_stage_queue_actor_redraw
7654    *
7655    * later during _clutter_stage_do_update, once relayouting is done
7656    * and the scenegraph has been updated we will call:
7657    * _clutter_stage_finish_queue_redraws
7658    *
7659    * _clutter_stage_finish_queue_redraws will call
7660    * _clutter_actor_finish_queue_redraw for each listed actor.
7661    * Note: actors *are* allowed to queue further redraws during this
7662    * process (considering clone actors or texture_new_from_actor which
7663    * respond to their source queueing a redraw by queuing a redraw
7664    * themselves). We repeat the process until the list is empty.
7665    *
7666    * This will result in the "queue-redraw" signal being fired for
7667    * each actor which will pass control to the default signal handler:
7668    * clutter_actor_real_queue_redraw
7669    *
7670    * This will bubble up to the stages handler:
7671    * clutter_stage_real_queue_redraw
7672    *
7673    * clutter_stage_real_queue_redraw will transform the actors paint
7674    * volume into screen space and add it as a clip region for the next
7675    * paint.
7676    */
7677
7678   /* ignore queueing a redraw for actors being destroyed */
7679   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7680     return;
7681
7682   stage = _clutter_actor_get_stage_internal (self);
7683
7684   /* Ignore queueing a redraw for actors not descended from a stage */
7685   if (stage == NULL)
7686     return;
7687
7688   /* ignore queueing a redraw on stages that are being destroyed */
7689   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7690     return;
7691
7692   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7693     {
7694       ClutterActorBox allocation_clip;
7695       ClutterVertex origin;
7696
7697       /* If the actor doesn't have a valid allocation then we will
7698        * queue a full stage redraw. */
7699       if (priv->needs_allocation)
7700         {
7701           /* NB: NULL denotes an undefined clip which will result in a
7702            * full redraw... */
7703           _clutter_actor_set_queue_redraw_clip (self, NULL);
7704           _clutter_actor_signal_queue_redraw (self, self);
7705           return;
7706         }
7707
7708       _clutter_paint_volume_init_static (&allocation_pv, self);
7709       pv = &allocation_pv;
7710
7711       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7712
7713       origin.x = allocation_clip.x1;
7714       origin.y = allocation_clip.y1;
7715       origin.z = 0;
7716       clutter_paint_volume_set_origin (pv, &origin);
7717       clutter_paint_volume_set_width (pv,
7718                                       allocation_clip.x2 - allocation_clip.x1);
7719       clutter_paint_volume_set_height (pv,
7720                                        allocation_clip.y2 -
7721                                        allocation_clip.y1);
7722       should_free_pv = TRUE;
7723     }
7724   else
7725     {
7726       pv = volume;
7727       should_free_pv = FALSE;
7728     }
7729
7730   self->priv->queue_redraw_entry =
7731     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7732                                        priv->queue_redraw_entry,
7733                                        self,
7734                                        pv);
7735
7736   if (should_free_pv)
7737     clutter_paint_volume_free (pv);
7738
7739   /* If this is the first redraw queued then we can directly use the
7740      effect parameter */
7741   if (!priv->is_dirty)
7742     priv->effect_to_redraw = effect;
7743   /* Otherwise we need to merge it with the existing effect parameter */
7744   else if (effect != NULL)
7745     {
7746       /* If there's already an effect then we need to use whichever is
7747          later in the chain of actors. Otherwise a full redraw has
7748          already been queued on the actor so we need to ignore the
7749          effect parameter */
7750       if (priv->effect_to_redraw != NULL)
7751         {
7752           if (priv->effects == NULL)
7753             g_warning ("Redraw queued with an effect that is "
7754                        "not applied to the actor");
7755           else
7756             {
7757               const GList *l;
7758
7759               for (l = _clutter_meta_group_peek_metas (priv->effects);
7760                    l != NULL;
7761                    l = l->next)
7762                 {
7763                   if (l->data == priv->effect_to_redraw ||
7764                       l->data == effect)
7765                     priv->effect_to_redraw = l->data;
7766                 }
7767             }
7768         }
7769     }
7770   else
7771     {
7772       /* If no effect is specified then we need to redraw the whole
7773          actor */
7774       priv->effect_to_redraw = NULL;
7775     }
7776
7777   priv->is_dirty = TRUE;
7778 }
7779
7780 /**
7781  * clutter_actor_queue_redraw:
7782  * @self: A #ClutterActor
7783  *
7784  * Queues up a redraw of an actor and any children. The redraw occurs
7785  * once the main loop becomes idle (after the current batch of events
7786  * has been processed, roughly).
7787  *
7788  * Applications rarely need to call this, as redraws are handled
7789  * automatically by modification functions.
7790  *
7791  * This function will not do anything if @self is not visible, or
7792  * if the actor is inside an invisible part of the scenegraph.
7793  *
7794  * Also be aware that painting is a NOP for actors with an opacity of
7795  * 0
7796  *
7797  * When you are implementing a custom actor you must queue a redraw
7798  * whenever some private state changes that will affect painting or
7799  * picking of your actor.
7800  */
7801 void
7802 clutter_actor_queue_redraw (ClutterActor *self)
7803 {
7804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7805
7806   _clutter_actor_queue_redraw_full (self,
7807                                     0, /* flags */
7808                                     NULL, /* clip volume */
7809                                     NULL /* effect */);
7810 }
7811
7812 /*< private >
7813  * _clutter_actor_queue_redraw_with_clip:
7814  * @self: A #ClutterActor
7815  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7816  *   this queue redraw.
7817  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7818  *   redrawn or %NULL if you are just using a @flag to state your
7819  *   desired clipping.
7820  *
7821  * Queues up a clipped redraw of an actor and any children. The redraw
7822  * occurs once the main loop becomes idle (after the current batch of
7823  * events has been processed, roughly).
7824  *
7825  * If no flags are given the clip volume is defined by @volume
7826  * specified in actor coordinates and tells Clutter that only content
7827  * within this volume has been changed so Clutter can optionally
7828  * optimize the redraw.
7829  *
7830  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7831  * should be %NULL and this tells Clutter to use the actor's current
7832  * allocation as a clip box. This flag can only be used for 2D actors,
7833  * because any actor with depth may be projected outside its
7834  * allocation.
7835  *
7836  * Applications rarely need to call this, as redraws are handled
7837  * automatically by modification functions.
7838  *
7839  * This function will not do anything if @self is not visible, or if
7840  * the actor is inside an invisible part of the scenegraph.
7841  *
7842  * Also be aware that painting is a NOP for actors with an opacity of
7843  * 0
7844  *
7845  * When you are implementing a custom actor you must queue a redraw
7846  * whenever some private state changes that will affect painting or
7847  * picking of your actor.
7848  */
7849 void
7850 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7851                                        ClutterRedrawFlags  flags,
7852                                        ClutterPaintVolume *volume)
7853 {
7854   _clutter_actor_queue_redraw_full (self,
7855                                     flags, /* flags */
7856                                     volume, /* clip volume */
7857                                     NULL /* effect */);
7858 }
7859
7860 static void
7861 _clutter_actor_queue_only_relayout (ClutterActor *self)
7862 {
7863   ClutterActorPrivate *priv = self->priv;
7864
7865   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7866     return;
7867
7868   if (priv->needs_width_request &&
7869       priv->needs_height_request &&
7870       priv->needs_allocation)
7871     return; /* save some cpu cycles */
7872
7873 #if CLUTTER_ENABLE_DEBUG
7874   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7875     {
7876       g_warning ("The actor '%s' is currently inside an allocation "
7877                  "cycle; calling clutter_actor_queue_relayout() is "
7878                  "not recommended",
7879                  _clutter_actor_get_debug_name (self));
7880     }
7881 #endif /* CLUTTER_ENABLE_DEBUG */
7882
7883   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7884 }
7885
7886 /**
7887  * clutter_actor_queue_redraw_with_clip:
7888  * @self: a #ClutterActor
7889  * @clip: (allow-none): a rectangular clip region, or %NULL
7890  *
7891  * Queues a redraw on @self limited to a specific, actor-relative
7892  * rectangular area.
7893  *
7894  * If @clip is %NULL this function is equivalent to
7895  * clutter_actor_queue_redraw().
7896  *
7897  * Since: 1.10
7898  */
7899 void
7900 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7901                                       const cairo_rectangle_int_t *clip)
7902 {
7903   ClutterPaintVolume volume;
7904   ClutterVertex origin;
7905
7906   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7907
7908   if (clip == NULL)
7909     {
7910       clutter_actor_queue_redraw (self);
7911       return;
7912     }
7913
7914   _clutter_paint_volume_init_static (&volume, self);
7915
7916   origin.x = clip->x;
7917   origin.y = clip->y;
7918   origin.z = 0.0f;
7919
7920   clutter_paint_volume_set_origin (&volume, &origin);
7921   clutter_paint_volume_set_width (&volume, clip->width);
7922   clutter_paint_volume_set_height (&volume, clip->height);
7923
7924   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7925
7926   clutter_paint_volume_free (&volume);
7927 }
7928
7929 /**
7930  * clutter_actor_queue_relayout:
7931  * @self: A #ClutterActor
7932  *
7933  * Indicates that the actor's size request or other layout-affecting
7934  * properties may have changed. This function is used inside #ClutterActor
7935  * subclass implementations, not by applications directly.
7936  *
7937  * Queueing a new layout automatically queues a redraw as well.
7938  *
7939  * Since: 0.8
7940  */
7941 void
7942 clutter_actor_queue_relayout (ClutterActor *self)
7943 {
7944   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7945
7946   _clutter_actor_queue_only_relayout (self);
7947   clutter_actor_queue_redraw (self);
7948 }
7949
7950 /**
7951  * clutter_actor_get_preferred_size:
7952  * @self: a #ClutterActor
7953  * @min_width_p: (out) (allow-none): return location for the minimum
7954  *   width, or %NULL
7955  * @min_height_p: (out) (allow-none): return location for the minimum
7956  *   height, or %NULL
7957  * @natural_width_p: (out) (allow-none): return location for the natural
7958  *   width, or %NULL
7959  * @natural_height_p: (out) (allow-none): return location for the natural
7960  *   height, or %NULL
7961  *
7962  * Computes the preferred minimum and natural size of an actor, taking into
7963  * account the actor's geometry management (either height-for-width
7964  * or width-for-height).
7965  *
7966  * The width and height used to compute the preferred height and preferred
7967  * width are the actor's natural ones.
7968  *
7969  * If you need to control the height for the preferred width, or the width for
7970  * the preferred height, you should use clutter_actor_get_preferred_width()
7971  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7972  * geometry management using the #ClutterActor:request-mode property.
7973  *
7974  * Since: 0.8
7975  */
7976 void
7977 clutter_actor_get_preferred_size (ClutterActor *self,
7978                                   gfloat       *min_width_p,
7979                                   gfloat       *min_height_p,
7980                                   gfloat       *natural_width_p,
7981                                   gfloat       *natural_height_p)
7982 {
7983   ClutterActorPrivate *priv;
7984   gfloat min_width, min_height;
7985   gfloat natural_width, natural_height;
7986
7987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7988
7989   priv = self->priv;
7990
7991   min_width = min_height = 0;
7992   natural_width = natural_height = 0;
7993
7994   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7995     {
7996       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7997       clutter_actor_get_preferred_width (self, -1,
7998                                          &min_width,
7999                                          &natural_width);
8000       clutter_actor_get_preferred_height (self, natural_width,
8001                                           &min_height,
8002                                           &natural_height);
8003     }
8004   else
8005     {
8006       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
8007       clutter_actor_get_preferred_height (self, -1,
8008                                           &min_height,
8009                                           &natural_height);
8010       clutter_actor_get_preferred_width (self, natural_height,
8011                                          &min_width,
8012                                          &natural_width);
8013     }
8014
8015   if (min_width_p)
8016     *min_width_p = min_width;
8017
8018   if (min_height_p)
8019     *min_height_p = min_height;
8020
8021   if (natural_width_p)
8022     *natural_width_p = natural_width;
8023
8024   if (natural_height_p)
8025     *natural_height_p = natural_height;
8026 }
8027
8028 /*< private >
8029  * effective_align:
8030  * @align: a #ClutterActorAlign
8031  * @direction: a #ClutterTextDirection
8032  *
8033  * Retrieves the correct alignment depending on the text direction
8034  *
8035  * Return value: the effective alignment
8036  */
8037 static ClutterActorAlign
8038 effective_align (ClutterActorAlign    align,
8039                  ClutterTextDirection direction)
8040 {
8041   ClutterActorAlign res;
8042
8043   switch (align)
8044     {
8045     case CLUTTER_ACTOR_ALIGN_START:
8046       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8047           ? CLUTTER_ACTOR_ALIGN_END
8048           : CLUTTER_ACTOR_ALIGN_START;
8049       break;
8050
8051     case CLUTTER_ACTOR_ALIGN_END:
8052       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8053           ? CLUTTER_ACTOR_ALIGN_START
8054           : CLUTTER_ACTOR_ALIGN_END;
8055       break;
8056
8057     default:
8058       res = align;
8059       break;
8060     }
8061
8062   return res;
8063 }
8064
8065 /*< private >
8066  * _clutter_actor_get_effective_x_align:
8067  * @self: a #ClutterActor
8068  *
8069  * Retrieves the effective horizontal alignment, taking into
8070  * consideration the text direction of @self.
8071  *
8072  * Return value: the effective horizontal alignment
8073  */
8074 ClutterActorAlign
8075 _clutter_actor_get_effective_x_align (ClutterActor *self)
8076 {
8077   return effective_align (clutter_actor_get_x_align (self),
8078                           clutter_actor_get_text_direction (self));
8079 }
8080
8081 static inline void
8082 adjust_for_margin (float  margin_start,
8083                    float  margin_end,
8084                    float *minimum_size,
8085                    float *natural_size,
8086                    float *allocated_start,
8087                    float *allocated_end)
8088 {
8089   *minimum_size -= (margin_start + margin_end);
8090   *natural_size -= (margin_start + margin_end);
8091   *allocated_start += margin_start;
8092   *allocated_end -= margin_end;
8093 }
8094
8095 static inline void
8096 adjust_for_alignment (ClutterActorAlign  alignment,
8097                       float              natural_size,
8098                       float             *allocated_start,
8099                       float             *allocated_end)
8100 {
8101   float allocated_size = *allocated_end - *allocated_start;
8102
8103   switch (alignment)
8104     {
8105     case CLUTTER_ACTOR_ALIGN_FILL:
8106       /* do nothing */
8107       break;
8108
8109     case CLUTTER_ACTOR_ALIGN_START:
8110       /* keep start */
8111       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8112       break;
8113
8114     case CLUTTER_ACTOR_ALIGN_END:
8115       if (allocated_size > natural_size)
8116         {
8117           *allocated_start += (allocated_size - natural_size);
8118           *allocated_end = *allocated_start + natural_size;
8119         }
8120       break;
8121
8122     case CLUTTER_ACTOR_ALIGN_CENTER:
8123       if (allocated_size > natural_size)
8124         {
8125           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8126           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8127         }
8128       break;
8129     }
8130 }
8131
8132 /*< private >
8133  * clutter_actor_adjust_width:
8134  * @self: a #ClutterActor
8135  * @minimum_width: (inout): the actor's preferred minimum width, which
8136  *   will be adjusted depending on the margin
8137  * @natural_width: (inout): the actor's preferred natural width, which
8138  *   will be adjusted depending on the margin
8139  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8140  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8141  *
8142  * Adjusts the preferred and allocated position and size of an actor,
8143  * depending on the margin and alignment properties.
8144  */
8145 static void
8146 clutter_actor_adjust_width (ClutterActor *self,
8147                             gfloat       *minimum_width,
8148                             gfloat       *natural_width,
8149                             gfloat       *adjusted_x1,
8150                             gfloat       *adjusted_x2)
8151 {
8152   ClutterTextDirection text_dir;
8153   const ClutterLayoutInfo *info;
8154
8155   info = _clutter_actor_get_layout_info_or_defaults (self);
8156   text_dir = clutter_actor_get_text_direction (self);
8157
8158   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8159
8160   /* this will tweak natural_width to remove the margin, so that
8161    * adjust_for_alignment() will use the correct size
8162    */
8163   adjust_for_margin (info->margin.left, info->margin.right,
8164                      minimum_width, natural_width,
8165                      adjusted_x1, adjusted_x2);
8166
8167   adjust_for_alignment (effective_align (info->x_align, text_dir),
8168                         *natural_width,
8169                         adjusted_x1, adjusted_x2);
8170 }
8171
8172 /*< private >
8173  * clutter_actor_adjust_height:
8174  * @self: a #ClutterActor
8175  * @minimum_height: (inout): the actor's preferred minimum height, which
8176  *   will be adjusted depending on the margin
8177  * @natural_height: (inout): the actor's preferred natural height, which
8178  *   will be adjusted depending on the margin
8179  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8180  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8181  *
8182  * Adjusts the preferred and allocated position and size of an actor,
8183  * depending on the margin and alignment properties.
8184  */
8185 static void
8186 clutter_actor_adjust_height (ClutterActor *self,
8187                              gfloat       *minimum_height,
8188                              gfloat       *natural_height,
8189                              gfloat       *adjusted_y1,
8190                              gfloat       *adjusted_y2)
8191 {
8192   const ClutterLayoutInfo *info;
8193
8194   info = _clutter_actor_get_layout_info_or_defaults (self);
8195
8196   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8197
8198   /* this will tweak natural_height to remove the margin, so that
8199    * adjust_for_alignment() will use the correct size
8200    */
8201   adjust_for_margin (info->margin.top, info->margin.bottom,
8202                      minimum_height, natural_height,
8203                      adjusted_y1,
8204                      adjusted_y2);
8205
8206   /* we don't use effective_align() here, because text direction
8207    * only affects the horizontal axis
8208    */
8209   adjust_for_alignment (info->y_align,
8210                         *natural_height,
8211                         adjusted_y1,
8212                         adjusted_y2);
8213
8214 }
8215
8216 /* looks for a cached size request for this for_size. If not
8217  * found, returns the oldest entry so it can be overwritten */
8218 static gboolean
8219 _clutter_actor_get_cached_size_request (gfloat         for_size,
8220                                         SizeRequest   *cached_size_requests,
8221                                         SizeRequest  **result)
8222 {
8223   guint i;
8224
8225   *result = &cached_size_requests[0];
8226
8227   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8228     {
8229       SizeRequest *sr;
8230
8231       sr = &cached_size_requests[i];
8232
8233       if (sr->age > 0 &&
8234           sr->for_size == for_size)
8235         {
8236           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8237           *result = sr;
8238           return TRUE;
8239         }
8240       else if (sr->age < (*result)->age)
8241         {
8242           *result = sr;
8243         }
8244     }
8245
8246   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8247
8248   return FALSE;
8249 }
8250
8251 /**
8252  * clutter_actor_get_preferred_width:
8253  * @self: A #ClutterActor
8254  * @for_height: available height when computing the preferred width,
8255  *   or a negative value to indicate that no height is defined
8256  * @min_width_p: (out) (allow-none): return location for minimum width,
8257  *   or %NULL
8258  * @natural_width_p: (out) (allow-none): return location for the natural
8259  *   width, or %NULL
8260  *
8261  * Computes the requested minimum and natural widths for an actor,
8262  * optionally depending on the specified height, or if they are
8263  * already computed, returns the cached values.
8264  *
8265  * An actor may not get its request - depending on the layout
8266  * manager that's in effect.
8267  *
8268  * A request should not incorporate the actor's scale or anchor point;
8269  * those transformations do not affect layout, only rendering.
8270  *
8271  * Since: 0.8
8272  */
8273 void
8274 clutter_actor_get_preferred_width (ClutterActor *self,
8275                                    gfloat        for_height,
8276                                    gfloat       *min_width_p,
8277                                    gfloat       *natural_width_p)
8278 {
8279   float request_min_width, request_natural_width;
8280   SizeRequest *cached_size_request;
8281   const ClutterLayoutInfo *info;
8282   ClutterActorPrivate *priv;
8283   gboolean found_in_cache;
8284
8285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8286
8287   priv = self->priv;
8288
8289   info = _clutter_actor_get_layout_info_or_defaults (self);
8290
8291   /* we shortcircuit the case of a fixed size set using set_width() */
8292   if (priv->min_width_set && priv->natural_width_set)
8293     {
8294       if (min_width_p != NULL)
8295         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8296
8297       if (natural_width_p != NULL)
8298         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8299
8300       return;
8301     }
8302
8303   /* the remaining cases are:
8304    *
8305    *   - either min_width or natural_width have been set
8306    *   - neither min_width or natural_width have been set
8307    *
8308    * in both cases, we go through the cache (and through the actor in case
8309    * of cache misses) and determine the authoritative value depending on
8310    * the *_set flags.
8311    */
8312
8313   if (!priv->needs_width_request)
8314     {
8315       found_in_cache =
8316         _clutter_actor_get_cached_size_request (for_height,
8317                                                 priv->width_requests,
8318                                                 &cached_size_request);
8319     }
8320   else
8321     {
8322       /* if the actor needs a width request we use the first slot */
8323       found_in_cache = FALSE;
8324       cached_size_request = &priv->width_requests[0];
8325     }
8326
8327   if (!found_in_cache)
8328     {
8329       gfloat minimum_width, natural_width;
8330       ClutterActorClass *klass;
8331
8332       minimum_width = natural_width = 0;
8333
8334       /* adjust for the margin */
8335       if (for_height >= 0)
8336         {
8337           for_height -= (info->margin.top + info->margin.bottom);
8338           if (for_height < 0)
8339             for_height = 0;
8340         }
8341
8342       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8343
8344       klass = CLUTTER_ACTOR_GET_CLASS (self);
8345       klass->get_preferred_width (self, for_height,
8346                                   &minimum_width,
8347                                   &natural_width);
8348
8349       /* adjust for the margin */
8350       minimum_width += (info->margin.left + info->margin.right);
8351       natural_width += (info->margin.left + info->margin.right);
8352
8353       /* Due to accumulated float errors, it's better not to warn
8354        * on this, but just fix it.
8355        */
8356       if (natural_width < minimum_width)
8357         natural_width = minimum_width;
8358
8359       cached_size_request->min_size = minimum_width;
8360       cached_size_request->natural_size = natural_width;
8361       cached_size_request->for_size = for_height;
8362       cached_size_request->age = priv->cached_width_age;
8363
8364       priv->cached_width_age += 1;
8365       priv->needs_width_request = FALSE;
8366     }
8367
8368   if (!priv->min_width_set)
8369     request_min_width = cached_size_request->min_size;
8370   else
8371     request_min_width = info->margin.left
8372                       + info->minimum.width
8373                       + info->margin.right;
8374
8375   if (!priv->natural_width_set)
8376     request_natural_width = cached_size_request->natural_size;
8377   else
8378     request_natural_width = info->margin.left
8379                           + info->natural.width
8380                           + info->margin.right;
8381
8382   if (min_width_p)
8383     *min_width_p = request_min_width;
8384
8385   if (natural_width_p)
8386     *natural_width_p = request_natural_width;
8387 }
8388
8389 /**
8390  * clutter_actor_get_preferred_height:
8391  * @self: A #ClutterActor
8392  * @for_width: available width to assume in computing desired height,
8393  *   or a negative value to indicate that no width is defined
8394  * @min_height_p: (out) (allow-none): return location for minimum height,
8395  *   or %NULL
8396  * @natural_height_p: (out) (allow-none): return location for natural
8397  *   height, or %NULL
8398  *
8399  * Computes the requested minimum and natural heights for an actor,
8400  * or if they are already computed, returns the cached values.
8401  *
8402  * An actor may not get its request - depending on the layout
8403  * manager that's in effect.
8404  *
8405  * A request should not incorporate the actor's scale or anchor point;
8406  * those transformations do not affect layout, only rendering.
8407  *
8408  * Since: 0.8
8409  */
8410 void
8411 clutter_actor_get_preferred_height (ClutterActor *self,
8412                                     gfloat        for_width,
8413                                     gfloat       *min_height_p,
8414                                     gfloat       *natural_height_p)
8415 {
8416   float request_min_height, request_natural_height;
8417   SizeRequest *cached_size_request;
8418   const ClutterLayoutInfo *info;
8419   ClutterActorPrivate *priv;
8420   gboolean found_in_cache;
8421
8422   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8423
8424   priv = self->priv;
8425
8426   info = _clutter_actor_get_layout_info_or_defaults (self);
8427
8428   /* we shortcircuit the case of a fixed size set using set_height() */
8429   if (priv->min_height_set && priv->natural_height_set)
8430     {
8431       if (min_height_p != NULL)
8432         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8433
8434       if (natural_height_p != NULL)
8435         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8436
8437       return;
8438     }
8439
8440   /* the remaining cases are:
8441    *
8442    *   - either min_height or natural_height have been set
8443    *   - neither min_height or natural_height have been set
8444    *
8445    * in both cases, we go through the cache (and through the actor in case
8446    * of cache misses) and determine the authoritative value depending on
8447    * the *_set flags.
8448    */
8449
8450   if (!priv->needs_height_request)
8451     {
8452       found_in_cache =
8453         _clutter_actor_get_cached_size_request (for_width,
8454                                                 priv->height_requests,
8455                                                 &cached_size_request);
8456     }
8457   else
8458     {
8459       found_in_cache = FALSE;
8460       cached_size_request = &priv->height_requests[0];
8461     }
8462
8463   if (!found_in_cache)
8464     {
8465       gfloat minimum_height, natural_height;
8466       ClutterActorClass *klass;
8467
8468       minimum_height = natural_height = 0;
8469
8470       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8471
8472       /* adjust for margin */
8473       if (for_width >= 0)
8474         {
8475           for_width -= (info->margin.left + info->margin.right);
8476           if (for_width < 0)
8477             for_width = 0;
8478         }
8479
8480       klass = CLUTTER_ACTOR_GET_CLASS (self);
8481       klass->get_preferred_height (self, for_width,
8482                                    &minimum_height,
8483                                    &natural_height);
8484
8485       /* adjust for margin */
8486       minimum_height += (info->margin.top + info->margin.bottom);
8487       natural_height += (info->margin.top + info->margin.bottom);
8488
8489       /* Due to accumulated float errors, it's better not to warn
8490        * on this, but just fix it.
8491        */
8492       if (natural_height < minimum_height)
8493         natural_height = minimum_height;
8494
8495       cached_size_request->min_size = minimum_height;
8496       cached_size_request->natural_size = natural_height;
8497       cached_size_request->for_size = for_width;
8498       cached_size_request->age = priv->cached_height_age;
8499
8500       priv->cached_height_age += 1;
8501       priv->needs_height_request = FALSE;
8502     }
8503
8504   if (!priv->min_height_set)
8505     request_min_height = cached_size_request->min_size;
8506   else
8507     request_min_height = info->margin.top
8508                        + info->minimum.height
8509                        + info->margin.bottom;
8510
8511   if (!priv->natural_height_set)
8512     request_natural_height = cached_size_request->natural_size;
8513   else
8514     request_natural_height = info->margin.top
8515                            + info->natural.height
8516                            + info->margin.bottom;
8517
8518   if (min_height_p)
8519     *min_height_p = request_min_height;
8520
8521   if (natural_height_p)
8522     *natural_height_p = request_natural_height;
8523 }
8524
8525 /**
8526  * clutter_actor_get_allocation_box:
8527  * @self: A #ClutterActor
8528  * @box: (out): the function fills this in with the actor's allocation
8529  *
8530  * Gets the layout box an actor has been assigned. The allocation can
8531  * only be assumed valid inside a paint() method; anywhere else, it
8532  * may be out-of-date.
8533  *
8534  * An allocation does not incorporate the actor's scale or anchor point;
8535  * those transformations do not affect layout, only rendering.
8536  *
8537  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8538  * of functions inside the implementation of the get_preferred_width()
8539  * or get_preferred_height() virtual functions.</note>
8540  *
8541  * Since: 0.8
8542  */
8543 void
8544 clutter_actor_get_allocation_box (ClutterActor    *self,
8545                                   ClutterActorBox *box)
8546 {
8547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8548
8549   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8550    * which limits calling get_allocation to inside paint() basically; or
8551    * we can 2) force a layout, which could be expensive if someone calls
8552    * get_allocation somewhere silly; or we can 3) just return the latest
8553    * value, allowing it to be out-of-date, and assume people know what
8554    * they are doing.
8555    *
8556    * The least-surprises approach that keeps existing code working is
8557    * likely to be 2). People can end up doing some inefficient things,
8558    * though, and in general code that requires 2) is probably broken.
8559    */
8560
8561   /* this implements 2) */
8562   if (G_UNLIKELY (self->priv->needs_allocation))
8563     {
8564       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8565
8566       /* do not queue a relayout on an unparented actor */
8567       if (stage)
8568         _clutter_stage_maybe_relayout (stage);
8569     }
8570
8571   /* commenting out the code above and just keeping this assigment
8572    * implements 3)
8573    */
8574   *box = self->priv->allocation;
8575 }
8576
8577 /**
8578  * clutter_actor_get_allocation_geometry:
8579  * @self: A #ClutterActor
8580  * @geom: (out): allocation geometry in pixels
8581  *
8582  * Gets the layout box an actor has been assigned.  The allocation can
8583  * only be assumed valid inside a paint() method; anywhere else, it
8584  * may be out-of-date.
8585  *
8586  * An allocation does not incorporate the actor's scale or anchor point;
8587  * those transformations do not affect layout, only rendering.
8588  *
8589  * The returned rectangle is in pixels.
8590  *
8591  * Since: 0.8
8592  */
8593 void
8594 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8595                                        ClutterGeometry *geom)
8596 {
8597   ClutterActorBox box;
8598
8599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8600   g_return_if_fail (geom != NULL);
8601
8602   clutter_actor_get_allocation_box (self, &box);
8603
8604   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8605   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8606   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8607   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8608 }
8609
8610 static void
8611 clutter_actor_update_constraints (ClutterActor    *self,
8612                                   ClutterActorBox *allocation)
8613 {
8614   ClutterActorPrivate *priv = self->priv;
8615   const GList *constraints, *l;
8616
8617   if (priv->constraints == NULL)
8618     return;
8619
8620   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8621   for (l = constraints; l != NULL; l = l->next)
8622     {
8623       ClutterConstraint *constraint = l->data;
8624       ClutterActorMeta *meta = l->data;
8625
8626       if (clutter_actor_meta_get_enabled (meta))
8627         {
8628           _clutter_constraint_update_allocation (constraint,
8629                                                  self,
8630                                                  allocation);
8631
8632           CLUTTER_NOTE (LAYOUT,
8633                         "Allocation of '%s' after constraint '%s': "
8634                         "{ %.2f, %.2f, %.2f, %.2f }",
8635                         _clutter_actor_get_debug_name (self),
8636                         _clutter_actor_meta_get_debug_name (meta),
8637                         allocation->x1,
8638                         allocation->y1,
8639                         allocation->x2,
8640                         allocation->y2);
8641         }
8642     }
8643 }
8644
8645 /*< private >
8646  * clutter_actor_adjust_allocation:
8647  * @self: a #ClutterActor
8648  * @allocation: (inout): the allocation to adjust
8649  *
8650  * Adjusts the passed allocation box taking into account the actor's
8651  * layout information, like alignment, expansion, and margin.
8652  */
8653 static void
8654 clutter_actor_adjust_allocation (ClutterActor    *self,
8655                                  ClutterActorBox *allocation)
8656 {
8657   ClutterActorBox adj_allocation;
8658   float alloc_width, alloc_height;
8659   float min_width, min_height;
8660   float nat_width, nat_height;
8661   ClutterRequestMode req_mode;
8662
8663   adj_allocation = *allocation;
8664
8665   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8666
8667   /* we want to hit the cache, so we use the public API */
8668   req_mode = clutter_actor_get_request_mode (self);
8669
8670   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8671     {
8672       clutter_actor_get_preferred_width (self, -1,
8673                                          &min_width,
8674                                          &nat_width);
8675       clutter_actor_get_preferred_height (self, alloc_width,
8676                                           &min_height,
8677                                           &nat_height);
8678     }
8679   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8680     {
8681       clutter_actor_get_preferred_height (self, -1,
8682                                           &min_height,
8683                                           &nat_height);
8684       clutter_actor_get_preferred_width (self, alloc_height,
8685                                          &min_width,
8686                                          &nat_width);
8687     }
8688
8689 #ifdef CLUTTER_ENABLE_DEBUG
8690   /* warn about underallocations */
8691   if (_clutter_diagnostic_enabled () &&
8692       (floorf (min_width - alloc_width) > 0 ||
8693        floorf (min_height - alloc_height) > 0))
8694     {
8695       ClutterActor *parent = clutter_actor_get_parent (self);
8696
8697       /* the only actors that are allowed to be underallocated are the Stage,
8698        * as it doesn't have an implicit size, and Actors that specifically
8699        * told us that they want to opt-out from layout control mechanisms
8700        * through the NO_LAYOUT escape hatch.
8701        */
8702       if (parent != NULL &&
8703           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8704         {
8705           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8706                      "of %.2f x %.2f from its parent actor '%s', but its "
8707                      "requested minimum size is of %.2f x %.2f",
8708                      _clutter_actor_get_debug_name (self),
8709                      alloc_width, alloc_height,
8710                      _clutter_actor_get_debug_name (parent),
8711                      min_width, min_height);
8712         }
8713     }
8714 #endif
8715
8716   clutter_actor_adjust_width (self,
8717                               &min_width,
8718                               &nat_width,
8719                               &adj_allocation.x1,
8720                               &adj_allocation.x2);
8721
8722   clutter_actor_adjust_height (self,
8723                                &min_height,
8724                                &nat_height,
8725                                &adj_allocation.y1,
8726                                &adj_allocation.y2);
8727
8728   /* we maintain the invariant that an allocation cannot be adjusted
8729    * to be outside the parent-given box
8730    */
8731   if (adj_allocation.x1 < allocation->x1 ||
8732       adj_allocation.y1 < allocation->y1 ||
8733       adj_allocation.x2 > allocation->x2 ||
8734       adj_allocation.y2 > allocation->y2)
8735     {
8736       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8737                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8738                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8739                  _clutter_actor_get_debug_name (self),
8740                  adj_allocation.x1, adj_allocation.y1,
8741                  adj_allocation.x2 - adj_allocation.x1,
8742                  adj_allocation.y2 - adj_allocation.y1,
8743                  allocation->x1, allocation->y1,
8744                  allocation->x2 - allocation->x1,
8745                  allocation->y2 - allocation->y1);
8746       return;
8747     }
8748
8749   *allocation = adj_allocation;
8750 }
8751
8752 static void
8753 clutter_actor_allocate_internal (ClutterActor           *self,
8754                                  const ClutterActorBox  *allocation,
8755                                  ClutterAllocationFlags  flags)
8756 {
8757   ClutterActorClass *klass;
8758
8759   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8760
8761   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8762                 _clutter_actor_get_debug_name (self));
8763
8764   klass = CLUTTER_ACTOR_GET_CLASS (self);
8765   klass->allocate (self, allocation, flags);
8766
8767   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8768
8769   clutter_actor_queue_redraw (self);
8770 }
8771
8772 /**
8773  * clutter_actor_allocate:
8774  * @self: A #ClutterActor
8775  * @box: new allocation of the actor, in parent-relative coordinates
8776  * @flags: flags that control the allocation
8777  *
8778  * Called by the parent of an actor to assign the actor its size.
8779  * Should never be called by applications (except when implementing
8780  * a container or layout manager).
8781  *
8782  * Actors can know from their allocation box whether they have moved
8783  * with respect to their parent actor. The @flags parameter describes
8784  * additional information about the allocation, for instance whether
8785  * the parent has moved with respect to the stage, for example because
8786  * a grandparent's origin has moved.
8787  *
8788  * Since: 0.8
8789  */
8790 void
8791 clutter_actor_allocate (ClutterActor           *self,
8792                         const ClutterActorBox  *box,
8793                         ClutterAllocationFlags  flags)
8794 {
8795   ClutterActorBox old_allocation, real_allocation;
8796   gboolean origin_changed, child_moved, size_changed;
8797   gboolean stage_allocation_changed;
8798   ClutterActorPrivate *priv;
8799
8800   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8801   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8802     {
8803       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8804                  "which isn't a descendent of the stage!\n",
8805                  self, _clutter_actor_get_debug_name (self));
8806       return;
8807     }
8808
8809   priv = self->priv;
8810
8811   old_allocation = priv->allocation;
8812   real_allocation = *box;
8813
8814   /* constraints are allowed to modify the allocation only here; we do
8815    * this prior to all the other checks so that we can bail out if the
8816    * allocation did not change
8817    */
8818   clutter_actor_update_constraints (self, &real_allocation);
8819
8820   /* adjust the allocation depending on the align/margin properties */
8821   clutter_actor_adjust_allocation (self, &real_allocation);
8822
8823   if (real_allocation.x2 < real_allocation.x1 ||
8824       real_allocation.y2 < real_allocation.y1)
8825     {
8826       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8827                  _clutter_actor_get_debug_name (self),
8828                  real_allocation.x2 - real_allocation.x1,
8829                  real_allocation.y2 - real_allocation.y1);
8830     }
8831
8832   /* we allow 0-sized actors, but not negative-sized ones */
8833   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8834   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8835
8836   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8837
8838   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8839                  real_allocation.y1 != old_allocation.y1);
8840
8841   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8842                   real_allocation.y2 != old_allocation.y2);
8843
8844   if (origin_changed || child_moved || size_changed)
8845     stage_allocation_changed = TRUE;
8846   else
8847     stage_allocation_changed = FALSE;
8848
8849   /* If we get an allocation "out of the blue"
8850    * (we did not queue relayout), then we want to
8851    * ignore it. But if we have needs_allocation set,
8852    * we want to guarantee that allocate() virtual
8853    * method is always called, i.e. that queue_relayout()
8854    * always results in an allocate() invocation on
8855    * an actor.
8856    *
8857    * The optimization here is to avoid re-allocating
8858    * actors that did not queue relayout and were
8859    * not moved.
8860    */
8861   if (!priv->needs_allocation && !stage_allocation_changed)
8862     {
8863       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8864       return;
8865     }
8866
8867   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8868    * clutter_actor_allocate(), it indicates whether the parent has its
8869    * absolute origin moved; when passed in to ClutterActor::allocate()
8870    * virtual method though, it indicates whether the child has its
8871    * absolute origin moved.  So we set it when child_moved is TRUE
8872    */
8873   if (child_moved)
8874     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8875
8876   /* store the flags here, so that they can be propagated by the
8877    * transition code
8878    */
8879   self->priv->allocation_flags = flags;
8880
8881   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8882     {
8883       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8884                                         &priv->allocation,
8885                                         &real_allocation);
8886     }
8887   else
8888     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8889                                       &real_allocation);
8890 }
8891
8892 /**
8893  * clutter_actor_set_allocation:
8894  * @self: a #ClutterActor
8895  * @box: a #ClutterActorBox
8896  * @flags: allocation flags
8897  *
8898  * Stores the allocation of @self as defined by @box.
8899  *
8900  * This function can only be called from within the implementation of
8901  * the #ClutterActorClass.allocate() virtual function.
8902  *
8903  * The allocation should have been adjusted to take into account constraints,
8904  * alignment, and margin properties. If you are implementing a #ClutterActor
8905  * subclass that provides its own layout management policy for its children
8906  * instead of using a #ClutterLayoutManager delegate, you should not call
8907  * this function on the children of @self; instead, you should call
8908  * clutter_actor_allocate(), which will adjust the allocation box for
8909  * you.
8910  *
8911  * This function should only be used by subclasses of #ClutterActor
8912  * that wish to store their allocation but cannot chain up to the
8913  * parent's implementation; the default implementation of the
8914  * #ClutterActorClass.allocate() virtual function will call this
8915  * function.
8916  *
8917  * It is important to note that, while chaining up was the recommended
8918  * behaviour for #ClutterActor subclasses prior to the introduction of
8919  * this function, it is recommended to call clutter_actor_set_allocation()
8920  * instead.
8921  *
8922  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8923  * to handle the allocation of its children, this function will call
8924  * the clutter_layout_manager_allocate() function only if the
8925  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8926  * expected that the subclass will call clutter_layout_manager_allocate()
8927  * by itself. For instance, the following code:
8928  *
8929  * |[
8930  * static void
8931  * my_actor_allocate (ClutterActor *actor,
8932  *                    const ClutterActorBox *allocation,
8933  *                    ClutterAllocationFlags flags)
8934  * {
8935  *   ClutterActorBox new_alloc;
8936  *   ClutterAllocationFlags new_flags;
8937  *
8938  *   adjust_allocation (allocation, &amp;new_alloc);
8939  *
8940  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8941  *
8942  *   /&ast; this will use the layout manager set on the actor &ast;/
8943  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8944  * }
8945  * ]|
8946  *
8947  * is equivalent to this:
8948  *
8949  * |[
8950  * static void
8951  * my_actor_allocate (ClutterActor *actor,
8952  *                    const ClutterActorBox *allocation,
8953  *                    ClutterAllocationFlags flags)
8954  * {
8955  *   ClutterLayoutManager *layout;
8956  *   ClutterActorBox new_alloc;
8957  *
8958  *   adjust_allocation (allocation, &amp;new_alloc);
8959  *
8960  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8961  *
8962  *   layout = clutter_actor_get_layout_manager (actor);
8963  *   clutter_layout_manager_allocate (layout,
8964  *                                    CLUTTER_CONTAINER (actor),
8965  *                                    &amp;new_alloc,
8966  *                                    flags);
8967  * }
8968  * ]|
8969  *
8970  * Since: 1.10
8971  */
8972 void
8973 clutter_actor_set_allocation (ClutterActor           *self,
8974                               const ClutterActorBox  *box,
8975                               ClutterAllocationFlags  flags)
8976 {
8977   ClutterActorPrivate *priv;
8978   gboolean changed;
8979
8980   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8981   g_return_if_fail (box != NULL);
8982
8983   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8984     {
8985       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8986                   "can only be called from within the implementation of "
8987                   "the ClutterActor::allocate() virtual function.");
8988       return;
8989     }
8990
8991   priv = self->priv;
8992
8993   g_object_freeze_notify (G_OBJECT (self));
8994
8995   changed = clutter_actor_set_allocation_internal (self, box, flags);
8996
8997   /* we allocate our children before we notify changes in our geometry,
8998    * so that people connecting to properties will be able to get valid
8999    * data out of the sub-tree of the scene graph that has this actor at
9000    * the root.
9001    */
9002   clutter_actor_maybe_layout_children (self, box, flags);
9003
9004   if (changed)
9005     {
9006       ClutterActorBox signal_box = priv->allocation;
9007       ClutterAllocationFlags signal_flags = priv->allocation_flags;
9008
9009       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
9010                      &signal_box,
9011                      signal_flags);
9012     }
9013
9014   g_object_thaw_notify (G_OBJECT (self));
9015 }
9016
9017 /**
9018  * clutter_actor_set_geometry:
9019  * @self: A #ClutterActor
9020  * @geometry: A #ClutterGeometry
9021  *
9022  * Sets the actor's fixed position and forces its minimum and natural
9023  * size, in pixels. This means the untransformed actor will have the
9024  * given geometry. This is the same as calling clutter_actor_set_position()
9025  * and clutter_actor_set_size().
9026  *
9027  * Deprecated: 1.10: Use clutter_actor_set_position() and
9028  *   clutter_actor_set_size() instead.
9029  */
9030 void
9031 clutter_actor_set_geometry (ClutterActor          *self,
9032                             const ClutterGeometry *geometry)
9033 {
9034   g_object_freeze_notify (G_OBJECT (self));
9035
9036   clutter_actor_set_position (self, geometry->x, geometry->y);
9037   clutter_actor_set_size (self, geometry->width, geometry->height);
9038
9039   g_object_thaw_notify (G_OBJECT (self));
9040 }
9041
9042 /**
9043  * clutter_actor_get_geometry:
9044  * @self: A #ClutterActor
9045  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9046  *
9047  * Gets the size and position of an actor relative to its parent
9048  * actor. This is the same as calling clutter_actor_get_position() and
9049  * clutter_actor_get_size(). It tries to "do what you mean" and get the
9050  * requested size and position if the actor's allocation is invalid.
9051  *
9052  * Deprecated: 1.10: Use clutter_actor_get_position() and
9053  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9054  *   instead.
9055  */
9056 void
9057 clutter_actor_get_geometry (ClutterActor    *self,
9058                             ClutterGeometry *geometry)
9059 {
9060   gfloat x, y, width, height;
9061
9062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9063   g_return_if_fail (geometry != NULL);
9064
9065   clutter_actor_get_position (self, &x, &y);
9066   clutter_actor_get_size (self, &width, &height);
9067
9068   geometry->x = (int) x;
9069   geometry->y = (int) y;
9070   geometry->width = (int) width;
9071   geometry->height = (int) height;
9072 }
9073
9074 /**
9075  * clutter_actor_set_position:
9076  * @self: A #ClutterActor
9077  * @x: New left position of actor in pixels.
9078  * @y: New top position of actor in pixels.
9079  *
9080  * Sets the actor's fixed position in pixels relative to any parent
9081  * actor.
9082  *
9083  * If a layout manager is in use, this position will override the
9084  * layout manager and force a fixed position.
9085  */
9086 void
9087 clutter_actor_set_position (ClutterActor *self,
9088                             gfloat        x,
9089                             gfloat        y)
9090 {
9091   ClutterPoint new_position;
9092
9093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9094
9095   clutter_point_init (&new_position, x, y);
9096
9097   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9098     {
9099       ClutterPoint cur_position;
9100
9101       cur_position.x = clutter_actor_get_x (self);
9102       cur_position.y = clutter_actor_get_y (self);
9103
9104       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9105                                         &cur_position,
9106                                         &new_position);
9107     }
9108   else
9109     _clutter_actor_update_transition (self,
9110                                       obj_props[PROP_POSITION],
9111                                       &new_position);
9112
9113   clutter_actor_queue_relayout (self);
9114 }
9115
9116 /**
9117  * clutter_actor_get_fixed_position_set:
9118  * @self: A #ClutterActor
9119  *
9120  * Checks whether an actor has a fixed position set (and will thus be
9121  * unaffected by any layout manager).
9122  *
9123  * Return value: %TRUE if the fixed position is set on the actor
9124  *
9125  * Since: 0.8
9126  */
9127 gboolean
9128 clutter_actor_get_fixed_position_set (ClutterActor *self)
9129 {
9130   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9131
9132   return self->priv->position_set;
9133 }
9134
9135 /**
9136  * clutter_actor_set_fixed_position_set:
9137  * @self: A #ClutterActor
9138  * @is_set: whether to use fixed position
9139  *
9140  * Sets whether an actor has a fixed position set (and will thus be
9141  * unaffected by any layout manager).
9142  *
9143  * Since: 0.8
9144  */
9145 void
9146 clutter_actor_set_fixed_position_set (ClutterActor *self,
9147                                       gboolean      is_set)
9148 {
9149   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9150
9151   if (self->priv->position_set == (is_set != FALSE))
9152     return;
9153
9154   if (!is_set)
9155     {
9156       ClutterLayoutInfo *info;
9157
9158       /* Ensure we set back the default fixed position of 0,0 so that setting
9159          just one of x/y always atomically gets 0 for the other */
9160       info = _clutter_actor_peek_layout_info (self);
9161       if (info != NULL)
9162         {
9163           info->fixed_pos.x = 0;
9164           info->fixed_pos.y = 0;
9165         }
9166     }
9167
9168   self->priv->position_set = is_set != FALSE;
9169   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9170
9171   clutter_actor_queue_relayout (self);
9172 }
9173
9174 /**
9175  * clutter_actor_move_by:
9176  * @self: A #ClutterActor
9177  * @dx: Distance to move Actor on X axis.
9178  * @dy: Distance to move Actor on Y axis.
9179  *
9180  * Moves an actor by the specified distance relative to its current
9181  * position in pixels.
9182  *
9183  * This function modifies the fixed position of an actor and thus removes
9184  * it from any layout management. Another way to move an actor is with an
9185  * anchor point, see clutter_actor_set_anchor_point().
9186  *
9187  * Since: 0.2
9188  */
9189 void
9190 clutter_actor_move_by (ClutterActor *self,
9191                        gfloat        dx,
9192                        gfloat        dy)
9193 {
9194   const ClutterLayoutInfo *info;
9195   gfloat x, y;
9196
9197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9198
9199   info = _clutter_actor_get_layout_info_or_defaults (self);
9200   x = info->fixed_pos.x;
9201   y = info->fixed_pos.y;
9202
9203   clutter_actor_set_position (self, x + dx, y + dy);
9204 }
9205
9206 static void
9207 clutter_actor_set_min_width (ClutterActor *self,
9208                              gfloat        min_width)
9209 {
9210   ClutterActorPrivate *priv = self->priv;
9211   ClutterActorBox old = { 0, };
9212   ClutterLayoutInfo *info;
9213
9214   /* if we are setting the size on a top-level actor and the
9215    * backend only supports static top-levels (e.g. framebuffers)
9216    * then we ignore the passed value and we override it with
9217    * the stage implementation's preferred size.
9218    */
9219   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9220       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9221     return;
9222
9223   info = _clutter_actor_get_layout_info (self);
9224
9225   if (priv->min_width_set && min_width == info->minimum.width)
9226     return;
9227
9228   g_object_freeze_notify (G_OBJECT (self));
9229
9230   clutter_actor_store_old_geometry (self, &old);
9231
9232   info->minimum.width = min_width;
9233   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9234   clutter_actor_set_min_width_set (self, TRUE);
9235
9236   clutter_actor_notify_if_geometry_changed (self, &old);
9237
9238   g_object_thaw_notify (G_OBJECT (self));
9239
9240   clutter_actor_queue_relayout (self);
9241 }
9242
9243 static void
9244 clutter_actor_set_min_height (ClutterActor *self,
9245                               gfloat        min_height)
9246
9247 {
9248   ClutterActorPrivate *priv = self->priv;
9249   ClutterActorBox old = { 0, };
9250   ClutterLayoutInfo *info;
9251
9252   /* if we are setting the size on a top-level actor and the
9253    * backend only supports static top-levels (e.g. framebuffers)
9254    * then we ignore the passed value and we override it with
9255    * the stage implementation's preferred size.
9256    */
9257   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9258       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9259     return;
9260
9261   info = _clutter_actor_get_layout_info (self);
9262
9263   if (priv->min_height_set && min_height == info->minimum.height)
9264     return;
9265
9266   g_object_freeze_notify (G_OBJECT (self));
9267
9268   clutter_actor_store_old_geometry (self, &old);
9269
9270   info->minimum.height = min_height;
9271   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9272   clutter_actor_set_min_height_set (self, TRUE);
9273
9274   clutter_actor_notify_if_geometry_changed (self, &old);
9275
9276   g_object_thaw_notify (G_OBJECT (self));
9277
9278   clutter_actor_queue_relayout (self);
9279 }
9280
9281 static void
9282 clutter_actor_set_natural_width (ClutterActor *self,
9283                                  gfloat        natural_width)
9284 {
9285   ClutterActorPrivate *priv = self->priv;
9286   ClutterActorBox old = { 0, };
9287   ClutterLayoutInfo *info;
9288
9289   /* if we are setting the size on a top-level actor and the
9290    * backend only supports static top-levels (e.g. framebuffers)
9291    * then we ignore the passed value and we override it with
9292    * the stage implementation's preferred size.
9293    */
9294   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9295       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9296     return;
9297
9298   info = _clutter_actor_get_layout_info (self);
9299
9300   if (priv->natural_width_set && natural_width == info->natural.width)
9301     return;
9302
9303   g_object_freeze_notify (G_OBJECT (self));
9304
9305   clutter_actor_store_old_geometry (self, &old);
9306
9307   info->natural.width = natural_width;
9308   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9309   clutter_actor_set_natural_width_set (self, TRUE);
9310
9311   clutter_actor_notify_if_geometry_changed (self, &old);
9312
9313   g_object_thaw_notify (G_OBJECT (self));
9314
9315   clutter_actor_queue_relayout (self);
9316 }
9317
9318 static void
9319 clutter_actor_set_natural_height (ClutterActor *self,
9320                                   gfloat        natural_height)
9321 {
9322   ClutterActorPrivate *priv = self->priv;
9323   ClutterActorBox old = { 0, };
9324   ClutterLayoutInfo *info;
9325
9326   /* if we are setting the size on a top-level actor and the
9327    * backend only supports static top-levels (e.g. framebuffers)
9328    * then we ignore the passed value and we override it with
9329    * the stage implementation's preferred size.
9330    */
9331   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9332       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9333     return;
9334
9335   info = _clutter_actor_get_layout_info (self);
9336
9337   if (priv->natural_height_set && natural_height == info->natural.height)
9338     return;
9339
9340   g_object_freeze_notify (G_OBJECT (self));
9341
9342   clutter_actor_store_old_geometry (self, &old);
9343
9344   info->natural.height = natural_height;
9345   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9346   clutter_actor_set_natural_height_set (self, TRUE);
9347
9348   clutter_actor_notify_if_geometry_changed (self, &old);
9349
9350   g_object_thaw_notify (G_OBJECT (self));
9351
9352   clutter_actor_queue_relayout (self);
9353 }
9354
9355 static void
9356 clutter_actor_set_min_width_set (ClutterActor *self,
9357                                  gboolean      use_min_width)
9358 {
9359   ClutterActorPrivate *priv = self->priv;
9360   ClutterActorBox old = { 0, };
9361
9362   if (priv->min_width_set == (use_min_width != FALSE))
9363     return;
9364
9365   clutter_actor_store_old_geometry (self, &old);
9366
9367   priv->min_width_set = use_min_width != FALSE;
9368   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9369
9370   clutter_actor_notify_if_geometry_changed (self, &old);
9371
9372   clutter_actor_queue_relayout (self);
9373 }
9374
9375 static void
9376 clutter_actor_set_min_height_set (ClutterActor *self,
9377                                   gboolean      use_min_height)
9378 {
9379   ClutterActorPrivate *priv = self->priv;
9380   ClutterActorBox old = { 0, };
9381
9382   if (priv->min_height_set == (use_min_height != FALSE))
9383     return;
9384
9385   clutter_actor_store_old_geometry (self, &old);
9386
9387   priv->min_height_set = use_min_height != FALSE;
9388   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9389
9390   clutter_actor_notify_if_geometry_changed (self, &old);
9391
9392   clutter_actor_queue_relayout (self);
9393 }
9394
9395 static void
9396 clutter_actor_set_natural_width_set (ClutterActor *self,
9397                                      gboolean      use_natural_width)
9398 {
9399   ClutterActorPrivate *priv = self->priv;
9400   ClutterActorBox old = { 0, };
9401
9402   if (priv->natural_width_set == (use_natural_width != FALSE))
9403     return;
9404
9405   clutter_actor_store_old_geometry (self, &old);
9406
9407   priv->natural_width_set = use_natural_width != FALSE;
9408   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9409
9410   clutter_actor_notify_if_geometry_changed (self, &old);
9411
9412   clutter_actor_queue_relayout (self);
9413 }
9414
9415 static void
9416 clutter_actor_set_natural_height_set (ClutterActor *self,
9417                                       gboolean      use_natural_height)
9418 {
9419   ClutterActorPrivate *priv = self->priv;
9420   ClutterActorBox old = { 0, };
9421
9422   if (priv->natural_height_set == (use_natural_height != FALSE))
9423     return;
9424
9425   clutter_actor_store_old_geometry (self, &old);
9426
9427   priv->natural_height_set = use_natural_height != FALSE;
9428   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9429
9430   clutter_actor_notify_if_geometry_changed (self, &old);
9431
9432   clutter_actor_queue_relayout (self);
9433 }
9434
9435 /**
9436  * clutter_actor_set_request_mode:
9437  * @self: a #ClutterActor
9438  * @mode: the request mode
9439  *
9440  * Sets the geometry request mode of @self.
9441  *
9442  * The @mode determines the order for invoking
9443  * clutter_actor_get_preferred_width() and
9444  * clutter_actor_get_preferred_height()
9445  *
9446  * Since: 1.2
9447  */
9448 void
9449 clutter_actor_set_request_mode (ClutterActor       *self,
9450                                 ClutterRequestMode  mode)
9451 {
9452   ClutterActorPrivate *priv;
9453
9454   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9455
9456   priv = self->priv;
9457
9458   if (priv->request_mode == mode)
9459     return;
9460
9461   priv->request_mode = mode;
9462
9463   priv->needs_width_request = TRUE;
9464   priv->needs_height_request = TRUE;
9465
9466   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9467
9468   clutter_actor_queue_relayout (self);
9469 }
9470
9471 /**
9472  * clutter_actor_get_request_mode:
9473  * @self: a #ClutterActor
9474  *
9475  * Retrieves the geometry request mode of @self
9476  *
9477  * Return value: the request mode for the actor
9478  *
9479  * Since: 1.2
9480  */
9481 ClutterRequestMode
9482 clutter_actor_get_request_mode (ClutterActor *self)
9483 {
9484   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9485                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9486
9487   return self->priv->request_mode;
9488 }
9489
9490 /* variant of set_width() without checks and without notification
9491  * freeze+thaw, for internal usage only
9492  */
9493 static inline void
9494 clutter_actor_set_width_internal (ClutterActor *self,
9495                                   gfloat        width)
9496 {
9497   if (width >= 0)
9498     {
9499       /* the Stage will use the :min-width to control the minimum
9500        * width to be resized to, so we should not be setting it
9501        * along with the :natural-width
9502        */
9503       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9504         clutter_actor_set_min_width (self, width);
9505
9506       clutter_actor_set_natural_width (self, width);
9507     }
9508   else
9509     {
9510       /* we only unset the :natural-width for the Stage */
9511       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9512         clutter_actor_set_min_width_set (self, FALSE);
9513
9514       clutter_actor_set_natural_width_set (self, FALSE);
9515     }
9516 }
9517
9518 /* variant of set_height() without checks and without notification
9519  * freeze+thaw, for internal usage only
9520  */
9521 static inline void
9522 clutter_actor_set_height_internal (ClutterActor *self,
9523                                    gfloat        height)
9524 {
9525   if (height >= 0)
9526     {
9527       /* see the comment above in set_width_internal() */
9528       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9529         clutter_actor_set_min_height (self, height);
9530
9531       clutter_actor_set_natural_height (self, height);
9532     }
9533   else
9534     {
9535       /* see the comment above in set_width_internal() */
9536       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9537         clutter_actor_set_min_height_set (self, FALSE);
9538
9539       clutter_actor_set_natural_height_set (self, FALSE);
9540     }
9541 }
9542
9543 static void
9544 clutter_actor_set_size_internal (ClutterActor      *self,
9545                                  const ClutterSize *size)
9546 {
9547   if (size != NULL)
9548     {
9549       clutter_actor_set_width_internal (self, size->width);
9550       clutter_actor_set_height_internal (self, size->height);
9551     }
9552   else
9553     {
9554       clutter_actor_set_width_internal (self, -1);
9555       clutter_actor_set_height_internal (self, -1);
9556     }
9557 }
9558
9559 /**
9560  * clutter_actor_set_size:
9561  * @self: A #ClutterActor
9562  * @width: New width of actor in pixels, or -1
9563  * @height: New height of actor in pixels, or -1
9564  *
9565  * Sets the actor's size request in pixels. This overrides any
9566  * "normal" size request the actor would have. For example
9567  * a text actor might normally request the size of the text;
9568  * this function would force a specific size instead.
9569  *
9570  * If @width and/or @height are -1 the actor will use its
9571  * "normal" size request instead of overriding it, i.e.
9572  * you can "unset" the size with -1.
9573  *
9574  * This function sets or unsets both the minimum and natural size.
9575  */
9576 void
9577 clutter_actor_set_size (ClutterActor *self,
9578                         gfloat        width,
9579                         gfloat        height)
9580 {
9581   ClutterSize new_size;
9582
9583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9584
9585   clutter_size_init (&new_size, width, height);
9586
9587   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9588     {
9589       /* minor optimization: if we don't have a duration then we can
9590        * skip the get_size() below, to avoid the chance of going through
9591        * get_preferred_width() and get_preferred_height() just to jump to
9592        * a new desired size
9593        */
9594       if (clutter_actor_get_easing_duration (self) == 0)
9595         {
9596           g_object_freeze_notify (G_OBJECT (self));
9597
9598           clutter_actor_set_size_internal (self, &new_size);
9599
9600           g_object_thaw_notify (G_OBJECT (self));
9601
9602           return;
9603         }
9604       else
9605         {
9606           ClutterSize cur_size;
9607
9608           clutter_size_init (&cur_size,
9609                              clutter_actor_get_width (self),
9610                              clutter_actor_get_height (self));
9611
9612          _clutter_actor_create_transition (self,
9613                                            obj_props[PROP_SIZE],
9614                                            &cur_size,
9615                                            &new_size);
9616         }
9617     }
9618   else
9619     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9620
9621   clutter_actor_queue_relayout (self);
9622 }
9623
9624 /**
9625  * clutter_actor_get_size:
9626  * @self: A #ClutterActor
9627  * @width: (out) (allow-none): return location for the width, or %NULL.
9628  * @height: (out) (allow-none): return location for the height, or %NULL.
9629  *
9630  * This function tries to "do what you mean" and return
9631  * the size an actor will have. If the actor has a valid
9632  * allocation, the allocation will be returned; otherwise,
9633  * the actors natural size request will be returned.
9634  *
9635  * If you care whether you get the request vs. the allocation, you
9636  * should probably call a different function like
9637  * clutter_actor_get_allocation_box() or
9638  * clutter_actor_get_preferred_width().
9639  *
9640  * Since: 0.2
9641  */
9642 void
9643 clutter_actor_get_size (ClutterActor *self,
9644                         gfloat       *width,
9645                         gfloat       *height)
9646 {
9647   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9648
9649   if (width)
9650     *width = clutter_actor_get_width (self);
9651
9652   if (height)
9653     *height = clutter_actor_get_height (self);
9654 }
9655
9656 /**
9657  * clutter_actor_get_position:
9658  * @self: a #ClutterActor
9659  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9660  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9661  *
9662  * This function tries to "do what you mean" and tell you where the
9663  * actor is, prior to any transformations. Retrieves the fixed
9664  * position of an actor in pixels, if one has been set; otherwise, if
9665  * the allocation is valid, returns the actor's allocated position;
9666  * otherwise, returns 0,0.
9667  *
9668  * The returned position is in pixels.
9669  *
9670  * Since: 0.6
9671  */
9672 void
9673 clutter_actor_get_position (ClutterActor *self,
9674                             gfloat       *x,
9675                             gfloat       *y)
9676 {
9677   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9678
9679   if (x)
9680     *x = clutter_actor_get_x (self);
9681
9682   if (y)
9683     *y = clutter_actor_get_y (self);
9684 }
9685
9686 /**
9687  * clutter_actor_get_transformed_position:
9688  * @self: A #ClutterActor
9689  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9690  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9691  *
9692  * Gets the absolute position of an actor, in pixels relative to the stage.
9693  *
9694  * Since: 0.8
9695  */
9696 void
9697 clutter_actor_get_transformed_position (ClutterActor *self,
9698                                         gfloat       *x,
9699                                         gfloat       *y)
9700 {
9701   ClutterVertex v1;
9702   ClutterVertex v2;
9703
9704   v1.x = v1.y = v1.z = 0;
9705   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9706
9707   if (x)
9708     *x = v2.x;
9709
9710   if (y)
9711     *y = v2.y;
9712 }
9713
9714 /**
9715  * clutter_actor_get_transformed_size:
9716  * @self: A #ClutterActor
9717  * @width: (out) (allow-none): return location for the width, or %NULL
9718  * @height: (out) (allow-none): return location for the height, or %NULL
9719  *
9720  * Gets the absolute size of an actor in pixels, taking into account the
9721  * scaling factors.
9722  *
9723  * If the actor has a valid allocation, the allocated size will be used.
9724  * If the actor has not a valid allocation then the preferred size will
9725  * be transformed and returned.
9726  *
9727  * If you want the transformed allocation, see
9728  * clutter_actor_get_abs_allocation_vertices() instead.
9729  *
9730  * <note>When the actor (or one of its ancestors) is rotated around the
9731  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9732  * as a generic quadrangle; in that case this function returns the size
9733  * of the smallest rectangle that encapsulates the entire quad. Please
9734  * note that in this case no assumptions can be made about the relative
9735  * position of this envelope to the absolute position of the actor, as
9736  * returned by clutter_actor_get_transformed_position(); if you need this
9737  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9738  * to get the coords of the actual quadrangle.</note>
9739  *
9740  * Since: 0.8
9741  */
9742 void
9743 clutter_actor_get_transformed_size (ClutterActor *self,
9744                                     gfloat       *width,
9745                                     gfloat       *height)
9746 {
9747   ClutterActorPrivate *priv;
9748   ClutterVertex v[4];
9749   gfloat x_min, x_max, y_min, y_max;
9750   gint i;
9751
9752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9753
9754   priv = self->priv;
9755
9756   /* if the actor hasn't been allocated yet, get the preferred
9757    * size and transform that
9758    */
9759   if (priv->needs_allocation)
9760     {
9761       gfloat natural_width, natural_height;
9762       ClutterActorBox box;
9763
9764       /* Make a fake allocation to transform.
9765        *
9766        * NB: _clutter_actor_transform_and_project_box expects a box in
9767        * the actor's coordinate space... */
9768
9769       box.x1 = 0;
9770       box.y1 = 0;
9771
9772       natural_width = natural_height = 0;
9773       clutter_actor_get_preferred_size (self, NULL, NULL,
9774                                         &natural_width,
9775                                         &natural_height);
9776
9777       box.x2 = natural_width;
9778       box.y2 = natural_height;
9779
9780       _clutter_actor_transform_and_project_box (self, &box, v);
9781     }
9782   else
9783     clutter_actor_get_abs_allocation_vertices (self, v);
9784
9785   x_min = x_max = v[0].x;
9786   y_min = y_max = v[0].y;
9787
9788   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9789     {
9790       if (v[i].x < x_min)
9791         x_min = v[i].x;
9792
9793       if (v[i].x > x_max)
9794         x_max = v[i].x;
9795
9796       if (v[i].y < y_min)
9797         y_min = v[i].y;
9798
9799       if (v[i].y > y_max)
9800         y_max = v[i].y;
9801     }
9802
9803   if (width)
9804     *width  = x_max - x_min;
9805
9806   if (height)
9807     *height = y_max - y_min;
9808 }
9809
9810 /**
9811  * clutter_actor_get_width:
9812  * @self: A #ClutterActor
9813  *
9814  * Retrieves the width of a #ClutterActor.
9815  *
9816  * If the actor has a valid allocation, this function will return the
9817  * width of the allocated area given to the actor.
9818  *
9819  * If the actor does not have a valid allocation, this function will
9820  * return the actor's natural width, that is the preferred width of
9821  * the actor.
9822  *
9823  * If you care whether you get the preferred width or the width that
9824  * has been assigned to the actor, you should probably call a different
9825  * function like clutter_actor_get_allocation_box() to retrieve the
9826  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9827  * preferred width.
9828  *
9829  * If an actor has a fixed width, for instance a width that has been
9830  * assigned using clutter_actor_set_width(), the width returned will
9831  * be the same value.
9832  *
9833  * Return value: the width of the actor, in pixels
9834  */
9835 gfloat
9836 clutter_actor_get_width (ClutterActor *self)
9837 {
9838   ClutterActorPrivate *priv;
9839
9840   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9841
9842   priv = self->priv;
9843
9844   if (priv->needs_allocation)
9845     {
9846       gfloat natural_width = 0;
9847
9848       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9849         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9850       else
9851         {
9852           gfloat natural_height = 0;
9853
9854           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9855           clutter_actor_get_preferred_width (self, natural_height,
9856                                              NULL,
9857                                              &natural_width);
9858         }
9859
9860       return natural_width;
9861     }
9862   else
9863     return priv->allocation.x2 - priv->allocation.x1;
9864 }
9865
9866 /**
9867  * clutter_actor_get_height:
9868  * @self: A #ClutterActor
9869  *
9870  * Retrieves the height of a #ClutterActor.
9871  *
9872  * If the actor has a valid allocation, this function will return the
9873  * height of the allocated area given to the actor.
9874  *
9875  * If the actor does not have a valid allocation, this function will
9876  * return the actor's natural height, that is the preferred height of
9877  * the actor.
9878  *
9879  * If you care whether you get the preferred height or the height that
9880  * has been assigned to the actor, you should probably call a different
9881  * function like clutter_actor_get_allocation_box() to retrieve the
9882  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9883  * preferred height.
9884  *
9885  * If an actor has a fixed height, for instance a height that has been
9886  * assigned using clutter_actor_set_height(), the height returned will
9887  * be the same value.
9888  *
9889  * Return value: the height of the actor, in pixels
9890  */
9891 gfloat
9892 clutter_actor_get_height (ClutterActor *self)
9893 {
9894   ClutterActorPrivate *priv;
9895
9896   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9897
9898   priv = self->priv;
9899
9900   if (priv->needs_allocation)
9901     {
9902       gfloat natural_height = 0;
9903
9904       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9905         {
9906           gfloat natural_width = 0;
9907
9908           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9909           clutter_actor_get_preferred_height (self, natural_width,
9910                                               NULL, &natural_height);
9911         }
9912       else
9913         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9914
9915       return natural_height;
9916     }
9917   else
9918     return priv->allocation.y2 - priv->allocation.y1;
9919 }
9920
9921 /**
9922  * clutter_actor_set_width:
9923  * @self: A #ClutterActor
9924  * @width: Requested new width for the actor, in pixels, or -1
9925  *
9926  * Forces a width on an actor, causing the actor's preferred width
9927  * and height (if any) to be ignored.
9928  *
9929  * If @width is -1 the actor will use its preferred width request
9930  * instead of overriding it, i.e. you can "unset" the width with -1.
9931  *
9932  * This function sets both the minimum and natural size of the actor.
9933  *
9934  * since: 0.2
9935  */
9936 void
9937 clutter_actor_set_width (ClutterActor *self,
9938                          gfloat        width)
9939 {
9940   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9941
9942   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9943     {
9944       float cur_size;
9945
9946       /* minor optimization: if we don't have a duration
9947        * then we can skip the get_width() below, to avoid
9948        * the chance of going through get_preferred_width()
9949        * just to jump to a new desired width.
9950        */
9951       if (clutter_actor_get_easing_duration (self) == 0)
9952         {
9953           g_object_freeze_notify (G_OBJECT (self));
9954
9955           clutter_actor_set_width_internal (self, width);
9956
9957           g_object_thaw_notify (G_OBJECT (self));
9958
9959           return;
9960         }
9961       else
9962         cur_size = clutter_actor_get_width (self);
9963
9964       _clutter_actor_create_transition (self,
9965                                         obj_props[PROP_WIDTH],
9966                                         cur_size,
9967                                         width);
9968     }
9969   else
9970     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9971 }
9972
9973 /**
9974  * clutter_actor_set_height:
9975  * @self: A #ClutterActor
9976  * @height: Requested new height for the actor, in pixels, or -1
9977  *
9978  * Forces a height on an actor, causing the actor's preferred width
9979  * and height (if any) to be ignored.
9980  *
9981  * If @height is -1 the actor will use its preferred height instead of
9982  * overriding it, i.e. you can "unset" the height with -1.
9983  *
9984  * This function sets both the minimum and natural size of the actor.
9985  *
9986  * since: 0.2
9987  */
9988 void
9989 clutter_actor_set_height (ClutterActor *self,
9990                           gfloat        height)
9991 {
9992   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9993
9994   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9995     {
9996       float cur_size;
9997
9998       /* see the comment in clutter_actor_set_width() above */
9999       if (clutter_actor_get_easing_duration (self) == 0)
10000         {
10001           g_object_freeze_notify (G_OBJECT (self));
10002
10003           clutter_actor_set_height_internal (self, height);
10004
10005           g_object_thaw_notify (G_OBJECT (self));
10006
10007           return;
10008         }
10009       else
10010         cur_size = clutter_actor_get_height (self);
10011
10012       _clutter_actor_create_transition (self,
10013                                         obj_props[PROP_HEIGHT],
10014                                         cur_size,
10015                                         height);
10016     }
10017   else
10018     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
10019 }
10020
10021 static inline void
10022 clutter_actor_set_x_internal (ClutterActor *self,
10023                               float         x)
10024 {
10025   ClutterActorPrivate *priv = self->priv;
10026   ClutterLayoutInfo *linfo;
10027   ClutterActorBox old = { 0, };
10028
10029   linfo = _clutter_actor_get_layout_info (self);
10030
10031   if (priv->position_set && linfo->fixed_pos.x == x)
10032     return;
10033
10034   clutter_actor_store_old_geometry (self, &old);
10035
10036   linfo->fixed_pos.x = x;
10037   clutter_actor_set_fixed_position_set (self, TRUE);
10038
10039   clutter_actor_notify_if_geometry_changed (self, &old);
10040
10041   clutter_actor_queue_relayout (self);
10042 }
10043
10044 static inline void
10045 clutter_actor_set_y_internal (ClutterActor *self,
10046                               float         y)
10047 {
10048   ClutterActorPrivate *priv = self->priv;
10049   ClutterLayoutInfo *linfo;
10050   ClutterActorBox old = { 0, };
10051
10052   linfo = _clutter_actor_get_layout_info (self);
10053
10054   if (priv->position_set && linfo->fixed_pos.y == y)
10055     return;
10056
10057   clutter_actor_store_old_geometry (self, &old);
10058
10059   linfo->fixed_pos.y = y;
10060   clutter_actor_set_fixed_position_set (self, TRUE);
10061
10062   clutter_actor_notify_if_geometry_changed (self, &old);
10063
10064   clutter_actor_queue_relayout (self);
10065 }
10066
10067 static void
10068 clutter_actor_set_position_internal (ClutterActor       *self,
10069                                      const ClutterPoint *position)
10070 {
10071   ClutterActorPrivate *priv = self->priv;
10072   ClutterLayoutInfo *linfo;
10073   ClutterActorBox old = { 0, };
10074
10075   linfo = _clutter_actor_get_layout_info (self);
10076
10077   if (priv->position_set &&
10078       clutter_point_equals (position, &linfo->fixed_pos))
10079     return;
10080
10081   clutter_actor_store_old_geometry (self, &old);
10082
10083   if (position != NULL)
10084     {
10085       linfo->fixed_pos = *position;
10086       clutter_actor_set_fixed_position_set (self, TRUE);
10087     }
10088   else
10089     clutter_actor_set_fixed_position_set (self, FALSE);
10090
10091   clutter_actor_notify_if_geometry_changed (self, &old);
10092
10093   clutter_actor_queue_relayout (self);
10094 }
10095
10096 /**
10097  * clutter_actor_set_x:
10098  * @self: a #ClutterActor
10099  * @x: the actor's position on the X axis
10100  *
10101  * Sets the actor's X coordinate, relative to its parent, in pixels.
10102  *
10103  * Overrides any layout manager and forces a fixed position for
10104  * the actor.
10105  *
10106  * The #ClutterActor:x property is animatable.
10107  *
10108  * Since: 0.6
10109  */
10110 void
10111 clutter_actor_set_x (ClutterActor *self,
10112                      gfloat        x)
10113 {
10114   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10115
10116   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10117     {
10118       float cur_position = clutter_actor_get_x (self);
10119
10120       _clutter_actor_create_transition (self, obj_props[PROP_X],
10121                                         cur_position,
10122                                         x);
10123     }
10124   else
10125     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10126 }
10127
10128 /**
10129  * clutter_actor_set_y:
10130  * @self: a #ClutterActor
10131  * @y: the actor's position on the Y axis
10132  *
10133  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10134  *
10135  * Overrides any layout manager and forces a fixed position for
10136  * the actor.
10137  *
10138  * The #ClutterActor:y property is animatable.
10139  *
10140  * Since: 0.6
10141  */
10142 void
10143 clutter_actor_set_y (ClutterActor *self,
10144                      gfloat        y)
10145 {
10146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10147
10148   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10149     {
10150       float cur_position = clutter_actor_get_y (self);
10151
10152       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10153                                         cur_position,
10154                                         y);
10155     }
10156   else
10157     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10158 }
10159
10160 /**
10161  * clutter_actor_get_x:
10162  * @self: A #ClutterActor
10163  *
10164  * Retrieves the X coordinate of a #ClutterActor.
10165  *
10166  * This function tries to "do what you mean", by returning the
10167  * correct value depending on the actor's state.
10168  *
10169  * If the actor has a valid allocation, this function will return
10170  * the X coordinate of the origin of the allocation box.
10171  *
10172  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10173  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10174  * function will return that coordinate.
10175  *
10176  * If both the allocation and a fixed position are missing, this function
10177  * will return 0.
10178  *
10179  * Return value: the X coordinate, in pixels, ignoring any
10180  *   transformation (i.e. scaling, rotation)
10181  */
10182 gfloat
10183 clutter_actor_get_x (ClutterActor *self)
10184 {
10185   ClutterActorPrivate *priv;
10186
10187   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10188
10189   priv = self->priv;
10190
10191   if (priv->needs_allocation)
10192     {
10193       if (priv->position_set)
10194         {
10195           const ClutterLayoutInfo *info;
10196
10197           info = _clutter_actor_get_layout_info_or_defaults (self);
10198
10199           return info->fixed_pos.x;
10200         }
10201       else
10202         return 0;
10203     }
10204   else
10205     return priv->allocation.x1;
10206 }
10207
10208 /**
10209  * clutter_actor_get_y:
10210  * @self: A #ClutterActor
10211  *
10212  * Retrieves the Y coordinate of a #ClutterActor.
10213  *
10214  * This function tries to "do what you mean", by returning the
10215  * correct value depending on the actor's state.
10216  *
10217  * If the actor has a valid allocation, this function will return
10218  * the Y coordinate of the origin of the allocation box.
10219  *
10220  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10221  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10222  * function will return that coordinate.
10223  *
10224  * If both the allocation and a fixed position are missing, this function
10225  * will return 0.
10226  *
10227  * Return value: the Y coordinate, in pixels, ignoring any
10228  *   transformation (i.e. scaling, rotation)
10229  */
10230 gfloat
10231 clutter_actor_get_y (ClutterActor *self)
10232 {
10233   ClutterActorPrivate *priv;
10234
10235   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10236
10237   priv = self->priv;
10238
10239   if (priv->needs_allocation)
10240     {
10241       if (priv->position_set)
10242         {
10243           const ClutterLayoutInfo *info;
10244
10245           info = _clutter_actor_get_layout_info_or_defaults (self);
10246
10247           return info->fixed_pos.y;
10248         }
10249       else
10250         return 0;
10251     }
10252   else
10253     return priv->allocation.y1;
10254 }
10255
10256 /**
10257  * clutter_actor_set_scale:
10258  * @self: A #ClutterActor
10259  * @scale_x: double factor to scale actor by horizontally.
10260  * @scale_y: double factor to scale actor by vertically.
10261  *
10262  * Scales an actor with the given factors. The scaling is relative to
10263  * the scale center and the anchor point. The scale center is
10264  * unchanged by this function and defaults to 0,0.
10265  *
10266  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10267  * animatable.
10268  *
10269  * Since: 0.2
10270  */
10271 void
10272 clutter_actor_set_scale (ClutterActor *self,
10273                          gdouble       scale_x,
10274                          gdouble       scale_y)
10275 {
10276   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10277
10278   g_object_freeze_notify (G_OBJECT (self));
10279
10280   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10281   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10282
10283   g_object_thaw_notify (G_OBJECT (self));
10284 }
10285
10286 /**
10287  * clutter_actor_set_scale_full:
10288  * @self: A #ClutterActor
10289  * @scale_x: double factor to scale actor by horizontally.
10290  * @scale_y: double factor to scale actor by vertically.
10291  * @center_x: X coordinate of the center of the scale.
10292  * @center_y: Y coordinate of the center of the scale
10293  *
10294  * Scales an actor with the given factors around the given center
10295  * point. The center point is specified in pixels relative to the
10296  * anchor point (usually the top left corner of the actor).
10297  *
10298  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10299  * are animatable.
10300  *
10301  * Since: 1.0
10302  */
10303 void
10304 clutter_actor_set_scale_full (ClutterActor *self,
10305                               gdouble       scale_x,
10306                               gdouble       scale_y,
10307                               gfloat        center_x,
10308                               gfloat        center_y)
10309 {
10310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10311
10312   g_object_freeze_notify (G_OBJECT (self));
10313
10314   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10315   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10316   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10317   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10318
10319   g_object_thaw_notify (G_OBJECT (self));
10320 }
10321
10322 /**
10323  * clutter_actor_set_scale_with_gravity:
10324  * @self: A #ClutterActor
10325  * @scale_x: double factor to scale actor by horizontally.
10326  * @scale_y: double factor to scale actor by vertically.
10327  * @gravity: the location of the scale center expressed as a compass
10328  * direction.
10329  *
10330  * Scales an actor with the given factors around the given
10331  * center point. The center point is specified as one of the compass
10332  * directions in #ClutterGravity. For example, setting it to north
10333  * will cause the top of the actor to remain unchanged and the rest of
10334  * the actor to expand left, right and downwards.
10335  *
10336  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10337  * animatable.
10338  *
10339  * Since: 1.0
10340  */
10341 void
10342 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10343                                       gdouble         scale_x,
10344                                       gdouble         scale_y,
10345                                       ClutterGravity  gravity)
10346 {
10347   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10348
10349   g_object_freeze_notify (G_OBJECT (self));
10350
10351   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10352   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10353   clutter_actor_set_scale_gravity (self, gravity);
10354
10355   g_object_thaw_notify (G_OBJECT (self));
10356 }
10357
10358 /**
10359  * clutter_actor_get_scale:
10360  * @self: A #ClutterActor
10361  * @scale_x: (out) (allow-none): Location to store horizonal
10362  *   scale factor, or %NULL.
10363  * @scale_y: (out) (allow-none): Location to store vertical
10364  *   scale factor, or %NULL.
10365  *
10366  * Retrieves an actors scale factors.
10367  *
10368  * Since: 0.2
10369  */
10370 void
10371 clutter_actor_get_scale (ClutterActor *self,
10372                          gdouble      *scale_x,
10373                          gdouble      *scale_y)
10374 {
10375   const ClutterTransformInfo *info;
10376
10377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10378
10379   info = _clutter_actor_get_transform_info_or_defaults (self);
10380
10381   if (scale_x)
10382     *scale_x = info->scale_x;
10383
10384   if (scale_y)
10385     *scale_y = info->scale_y;
10386 }
10387
10388 /**
10389  * clutter_actor_get_scale_center:
10390  * @self: A #ClutterActor
10391  * @center_x: (out) (allow-none): Location to store the X position
10392  *   of the scale center, or %NULL.
10393  * @center_y: (out) (allow-none): Location to store the Y position
10394  *   of the scale center, or %NULL.
10395  *
10396  * Retrieves the scale center coordinate in pixels relative to the top
10397  * left corner of the actor. If the scale center was specified using a
10398  * #ClutterGravity this will calculate the pixel offset using the
10399  * current size of the actor.
10400  *
10401  * Since: 1.0
10402  */
10403 void
10404 clutter_actor_get_scale_center (ClutterActor *self,
10405                                 gfloat       *center_x,
10406                                 gfloat       *center_y)
10407 {
10408   const ClutterTransformInfo *info;
10409
10410   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10411
10412   info = _clutter_actor_get_transform_info_or_defaults (self);
10413
10414   clutter_anchor_coord_get_units (self, &info->scale_center,
10415                                   center_x,
10416                                   center_y,
10417                                   NULL);
10418 }
10419
10420 /**
10421  * clutter_actor_get_scale_gravity:
10422  * @self: A #ClutterActor
10423  *
10424  * Retrieves the scale center as a compass direction. If the scale
10425  * center was specified in pixels or units this will return
10426  * %CLUTTER_GRAVITY_NONE.
10427  *
10428  * Return value: the scale gravity
10429  *
10430  * Since: 1.0
10431  */
10432 ClutterGravity
10433 clutter_actor_get_scale_gravity (ClutterActor *self)
10434 {
10435   const ClutterTransformInfo *info;
10436
10437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10438
10439   info = _clutter_actor_get_transform_info_or_defaults (self);
10440
10441   return clutter_anchor_coord_get_gravity (&info->scale_center);
10442 }
10443
10444 static inline void
10445 clutter_actor_set_opacity_internal (ClutterActor *self,
10446                                     guint8        opacity)
10447 {
10448   ClutterActorPrivate *priv = self->priv;
10449
10450   if (priv->opacity != opacity)
10451     {
10452       priv->opacity = opacity;
10453
10454       /* Queue a redraw from the flatten effect so that it can use
10455          its cached image if available instead of having to redraw the
10456          actual actor. If it doesn't end up using the FBO then the
10457          effect is still able to continue the paint anyway. If there
10458          is no flatten effect yet then this is equivalent to queueing
10459          a full redraw */
10460       _clutter_actor_queue_redraw_full (self,
10461                                         0, /* flags */
10462                                         NULL, /* clip */
10463                                         priv->flatten_effect);
10464
10465       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10466     }
10467 }
10468
10469 /**
10470  * clutter_actor_set_opacity:
10471  * @self: A #ClutterActor
10472  * @opacity: New opacity value for the actor.
10473  *
10474  * Sets the actor's opacity, with zero being completely transparent and
10475  * 255 (0xff) being fully opaque.
10476  *
10477  * The #ClutterActor:opacity property is animatable.
10478  */
10479 void
10480 clutter_actor_set_opacity (ClutterActor *self,
10481                            guint8        opacity)
10482 {
10483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10484
10485   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10486     {
10487       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10488                                         self->priv->opacity,
10489                                         opacity);
10490     }
10491   else
10492     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10493 }
10494
10495 /*
10496  * clutter_actor_get_paint_opacity_internal:
10497  * @self: a #ClutterActor
10498  *
10499  * Retrieves the absolute opacity of the actor, as it appears on the stage
10500  *
10501  * This function does not do type checks
10502  *
10503  * Return value: the absolute opacity of the actor
10504  */
10505 static guint8
10506 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10507 {
10508   ClutterActorPrivate *priv = self->priv;
10509   ClutterActor *parent;
10510
10511   /* override the top-level opacity to always be 255; even in
10512    * case of ClutterStage:use-alpha being TRUE we want the rest
10513    * of the scene to be painted
10514    */
10515   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10516     return 255;
10517
10518   if (priv->opacity_override >= 0)
10519     return priv->opacity_override;
10520
10521   parent = priv->parent;
10522
10523   /* Factor in the actual actors opacity with parents */
10524   if (parent != NULL)
10525     {
10526       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10527
10528       if (opacity != 0xff)
10529         return (opacity * priv->opacity) / 0xff;
10530     }
10531
10532   return priv->opacity;
10533
10534 }
10535
10536 /**
10537  * clutter_actor_get_paint_opacity:
10538  * @self: A #ClutterActor
10539  *
10540  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10541  *
10542  * This function traverses the hierarchy chain and composites the opacity of
10543  * the actor with that of its parents.
10544  *
10545  * This function is intended for subclasses to use in the paint virtual
10546  * function, to paint themselves with the correct opacity.
10547  *
10548  * Return value: The actor opacity value.
10549  *
10550  * Since: 0.8
10551  */
10552 guint8
10553 clutter_actor_get_paint_opacity (ClutterActor *self)
10554 {
10555   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10556
10557   return clutter_actor_get_paint_opacity_internal (self);
10558 }
10559
10560 /**
10561  * clutter_actor_get_opacity:
10562  * @self: a #ClutterActor
10563  *
10564  * Retrieves the opacity value of an actor, as set by
10565  * clutter_actor_set_opacity().
10566  *
10567  * For retrieving the absolute opacity of the actor inside a paint
10568  * virtual function, see clutter_actor_get_paint_opacity().
10569  *
10570  * Return value: the opacity of the actor
10571  */
10572 guint8
10573 clutter_actor_get_opacity (ClutterActor *self)
10574 {
10575   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10576
10577   return self->priv->opacity;
10578 }
10579
10580 /**
10581  * clutter_actor_set_offscreen_redirect:
10582  * @self: A #ClutterActor
10583  * @redirect: New offscreen redirect flags for the actor.
10584  *
10585  * Defines the circumstances where the actor should be redirected into
10586  * an offscreen image. The offscreen image is used to flatten the
10587  * actor into a single image while painting for two main reasons.
10588  * Firstly, when the actor is painted a second time without any of its
10589  * contents changing it can simply repaint the cached image without
10590  * descending further down the actor hierarchy. Secondly, it will make
10591  * the opacity look correct even if there are overlapping primitives
10592  * in the actor.
10593  *
10594  * Caching the actor could in some cases be a performance win and in
10595  * some cases be a performance lose so it is important to determine
10596  * which value is right for an actor before modifying this value. For
10597  * example, there is never any reason to flatten an actor that is just
10598  * a single texture (such as a #ClutterTexture) because it is
10599  * effectively already cached in an image so the offscreen would be
10600  * redundant. Also if the actor contains primitives that are far apart
10601  * with a large transparent area in the middle (such as a large
10602  * CluterGroup with a small actor in the top left and a small actor in
10603  * the bottom right) then the cached image will contain the entire
10604  * image of the large area and the paint will waste time blending all
10605  * of the transparent pixels in the middle.
10606  *
10607  * The default method of implementing opacity on a container simply
10608  * forwards on the opacity to all of the children. If the children are
10609  * overlapping then it will appear as if they are two separate glassy
10610  * objects and there will be a break in the color where they
10611  * overlap. By redirecting to an offscreen buffer it will be as if the
10612  * two opaque objects are combined into one and then made transparent
10613  * which is usually what is expected.
10614  *
10615  * The image below demonstrates the difference between redirecting and
10616  * not. The image shows two Clutter groups, each containing a red and
10617  * a green rectangle which overlap. The opacity on the group is set to
10618  * 128 (which is 50%). When the offscreen redirect is not used, the
10619  * red rectangle can be seen through the blue rectangle as if the two
10620  * rectangles were separately transparent. When the redirect is used
10621  * the group as a whole is transparent instead so the red rectangle is
10622  * not visible where they overlap.
10623  *
10624  * <figure id="offscreen-redirect">
10625  *   <title>Sample of using an offscreen redirect for transparency</title>
10626  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10627  * </figure>
10628  *
10629  * The default value for this property is 0, so we effectively will
10630  * never redirect an actor offscreen by default. This means that there
10631  * are times that transparent actors may look glassy as described
10632  * above. The reason this is the default is because there is a
10633  * performance trade off between quality and performance here. In many
10634  * cases the default form of glassy opacity looks good enough, but if
10635  * it's not you will need to set the
10636  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10637  * redirection for opacity.
10638  *
10639  * Custom actors that don't contain any overlapping primitives are
10640  * recommended to override the has_overlaps() virtual to return %FALSE
10641  * for maximum efficiency.
10642  *
10643  * Since: 1.8
10644  */
10645 void
10646 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10647                                       ClutterOffscreenRedirect redirect)
10648 {
10649   ClutterActorPrivate *priv;
10650
10651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10652
10653   priv = self->priv;
10654
10655   if (priv->offscreen_redirect != redirect)
10656     {
10657       priv->offscreen_redirect = redirect;
10658
10659       /* Queue a redraw from the effect so that it can use its cached
10660          image if available instead of having to redraw the actual
10661          actor. If it doesn't end up using the FBO then the effect is
10662          still able to continue the paint anyway. If there is no
10663          effect then this is equivalent to queuing a full redraw */
10664       _clutter_actor_queue_redraw_full (self,
10665                                         0, /* flags */
10666                                         NULL, /* clip */
10667                                         priv->flatten_effect);
10668
10669       g_object_notify_by_pspec (G_OBJECT (self),
10670                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10671     }
10672 }
10673
10674 /**
10675  * clutter_actor_get_offscreen_redirect:
10676  * @self: a #ClutterActor
10677  *
10678  * Retrieves whether to redirect the actor to an offscreen buffer, as
10679  * set by clutter_actor_set_offscreen_redirect().
10680  *
10681  * Return value: the value of the offscreen-redirect property of the actor
10682  *
10683  * Since: 1.8
10684  */
10685 ClutterOffscreenRedirect
10686 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10687 {
10688   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10689
10690   return self->priv->offscreen_redirect;
10691 }
10692
10693 /**
10694  * clutter_actor_set_name:
10695  * @self: A #ClutterActor
10696  * @name: Textual tag to apply to actor
10697  *
10698  * Sets the given name to @self. The name can be used to identify
10699  * a #ClutterActor.
10700  */
10701 void
10702 clutter_actor_set_name (ClutterActor *self,
10703                         const gchar  *name)
10704 {
10705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10706
10707   g_free (self->priv->name);
10708   self->priv->name = g_strdup (name);
10709
10710   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10711 }
10712
10713 /**
10714  * clutter_actor_get_name:
10715  * @self: A #ClutterActor
10716  *
10717  * Retrieves the name of @self.
10718  *
10719  * Return value: the name of the actor, or %NULL. The returned string is
10720  *   owned by the actor and should not be modified or freed.
10721  */
10722 const gchar *
10723 clutter_actor_get_name (ClutterActor *self)
10724 {
10725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10726
10727   return self->priv->name;
10728 }
10729
10730 /**
10731  * clutter_actor_get_gid:
10732  * @self: A #ClutterActor
10733  *
10734  * Retrieves the unique id for @self.
10735  *
10736  * Return value: Globally unique value for this object instance.
10737  *
10738  * Since: 0.6
10739  *
10740  * Deprecated: 1.8: The id is not used any longer.
10741  */
10742 guint32
10743 clutter_actor_get_gid (ClutterActor *self)
10744 {
10745   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10746
10747   return self->priv->id;
10748 }
10749
10750 static inline void
10751 clutter_actor_set_depth_internal (ClutterActor *self,
10752                                   float         depth)
10753 {
10754   ClutterTransformInfo *info;
10755
10756   info = _clutter_actor_get_transform_info (self);
10757
10758   if (info->depth != depth)
10759     {
10760       /* Sets Z value - XXX 2.0: should we invert? */
10761       info->depth = depth;
10762
10763       self->priv->transform_valid = FALSE;
10764
10765       /* FIXME - remove this crap; sadly, there are still containers
10766        * in Clutter that depend on this utter brain damage
10767        */
10768       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10769
10770       clutter_actor_queue_redraw (self);
10771
10772       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10773     }
10774 }
10775
10776 /**
10777  * clutter_actor_set_depth:
10778  * @self: a #ClutterActor
10779  * @depth: Z co-ord
10780  *
10781  * Sets the Z coordinate of @self to @depth.
10782  *
10783  * The unit used by @depth is dependant on the perspective setup. See
10784  * also clutter_stage_set_perspective().
10785  */
10786 void
10787 clutter_actor_set_depth (ClutterActor *self,
10788                          gfloat        depth)
10789 {
10790   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10791
10792   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10793     {
10794       const ClutterTransformInfo *info;
10795
10796       info = _clutter_actor_get_transform_info_or_defaults (self);
10797
10798       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10799                                         info->depth,
10800                                         depth);
10801     }
10802   else
10803     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10804
10805   clutter_actor_queue_redraw (self);
10806 }
10807
10808 /**
10809  * clutter_actor_get_depth:
10810  * @self: a #ClutterActor
10811  *
10812  * Retrieves the depth of @self.
10813  *
10814  * Return value: the depth of the actor
10815  */
10816 gfloat
10817 clutter_actor_get_depth (ClutterActor *self)
10818 {
10819   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10820
10821   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10822 }
10823
10824 /**
10825  * clutter_actor_set_rotation:
10826  * @self: a #ClutterActor
10827  * @axis: the axis of rotation
10828  * @angle: the angle of rotation
10829  * @x: X coordinate of the rotation center
10830  * @y: Y coordinate of the rotation center
10831  * @z: Z coordinate of the rotation center
10832  *
10833  * Sets the rotation angle of @self around the given axis.
10834  *
10835  * The rotation center coordinates used depend on the value of @axis:
10836  * <itemizedlist>
10837  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10838  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10839  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10840  * </itemizedlist>
10841  *
10842  * The rotation coordinates are relative to the anchor point of the
10843  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10844  * point is set, the upper left corner is assumed as the origin.
10845  *
10846  * Since: 0.8
10847  */
10848 void
10849 clutter_actor_set_rotation (ClutterActor      *self,
10850                             ClutterRotateAxis  axis,
10851                             gdouble            angle,
10852                             gfloat             x,
10853                             gfloat             y,
10854                             gfloat             z)
10855 {
10856   ClutterVertex v;
10857
10858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10859
10860   v.x = x;
10861   v.y = y;
10862   v.z = z;
10863
10864   g_object_freeze_notify (G_OBJECT (self));
10865
10866   clutter_actor_set_rotation_angle (self, axis, angle);
10867   clutter_actor_set_rotation_center_internal (self, axis, &v);
10868
10869   g_object_thaw_notify (G_OBJECT (self));
10870 }
10871
10872 /**
10873  * clutter_actor_set_z_rotation_from_gravity:
10874  * @self: a #ClutterActor
10875  * @angle: the angle of rotation
10876  * @gravity: the center point of the rotation
10877  *
10878  * Sets the rotation angle of @self around the Z axis using the center
10879  * point specified as a compass point. For example to rotate such that
10880  * the center of the actor remains static you can use
10881  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10882  * will move accordingly.
10883  *
10884  * Since: 1.0
10885  */
10886 void
10887 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10888                                            gdouble         angle,
10889                                            ClutterGravity  gravity)
10890 {
10891   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10892
10893   if (gravity == CLUTTER_GRAVITY_NONE)
10894     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10895   else
10896     {
10897       GObject *obj = G_OBJECT (self);
10898       ClutterTransformInfo *info;
10899
10900       info = _clutter_actor_get_transform_info (self);
10901
10902       g_object_freeze_notify (obj);
10903
10904       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10905
10906       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10907       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10908       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10909
10910       g_object_thaw_notify (obj);
10911     }
10912 }
10913
10914 /**
10915  * clutter_actor_get_rotation:
10916  * @self: a #ClutterActor
10917  * @axis: the axis of rotation
10918  * @x: (out): return value for the X coordinate of the center of rotation
10919  * @y: (out): return value for the Y coordinate of the center of rotation
10920  * @z: (out): return value for the Z coordinate of the center of rotation
10921  *
10922  * Retrieves the angle and center of rotation on the given axis,
10923  * set using clutter_actor_set_rotation().
10924  *
10925  * Return value: the angle of rotation
10926  *
10927  * Since: 0.8
10928  */
10929 gdouble
10930 clutter_actor_get_rotation (ClutterActor      *self,
10931                             ClutterRotateAxis  axis,
10932                             gfloat            *x,
10933                             gfloat            *y,
10934                             gfloat            *z)
10935 {
10936   const ClutterTransformInfo *info;
10937   const AnchorCoord *anchor_coord;
10938   gdouble retval = 0;
10939
10940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10941
10942   info = _clutter_actor_get_transform_info_or_defaults (self);
10943
10944   switch (axis)
10945     {
10946     case CLUTTER_X_AXIS:
10947       anchor_coord = &info->rx_center;
10948       retval = info->rx_angle;
10949       break;
10950
10951     case CLUTTER_Y_AXIS:
10952       anchor_coord = &info->ry_center;
10953       retval = info->ry_angle;
10954       break;
10955
10956     case CLUTTER_Z_AXIS:
10957       anchor_coord = &info->rz_center;
10958       retval = info->rz_angle;
10959       break;
10960
10961     default:
10962       anchor_coord = NULL;
10963       retval = 0.0;
10964       break;
10965     }
10966
10967   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10968
10969   return retval;
10970 }
10971
10972 /**
10973  * clutter_actor_get_z_rotation_gravity:
10974  * @self: A #ClutterActor
10975  *
10976  * Retrieves the center for the rotation around the Z axis as a
10977  * compass direction. If the center was specified in pixels or units
10978  * this will return %CLUTTER_GRAVITY_NONE.
10979  *
10980  * Return value: the Z rotation center
10981  *
10982  * Since: 1.0
10983  */
10984 ClutterGravity
10985 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10986 {
10987   const ClutterTransformInfo *info;
10988
10989   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10990
10991   info = _clutter_actor_get_transform_info_or_defaults (self);
10992
10993   return clutter_anchor_coord_get_gravity (&info->rz_center);
10994 }
10995
10996 /**
10997  * clutter_actor_set_clip:
10998  * @self: A #ClutterActor
10999  * @xoff: X offset of the clip rectangle
11000  * @yoff: Y offset of the clip rectangle
11001  * @width: Width of the clip rectangle
11002  * @height: Height of the clip rectangle
11003  *
11004  * Sets clip area for @self. The clip area is always computed from the
11005  * upper left corner of the actor, even if the anchor point is set
11006  * otherwise.
11007  *
11008  * Since: 0.6
11009  */
11010 void
11011 clutter_actor_set_clip (ClutterActor *self,
11012                         gfloat        xoff,
11013                         gfloat        yoff,
11014                         gfloat        width,
11015                         gfloat        height)
11016 {
11017   ClutterActorPrivate *priv;
11018
11019   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11020
11021   priv = self->priv;
11022
11023   if (priv->has_clip &&
11024       priv->clip.x == xoff &&
11025       priv->clip.y == yoff &&
11026       priv->clip.width == width &&
11027       priv->clip.height == height)
11028     return;
11029
11030   priv->clip.x = xoff;
11031   priv->clip.y = yoff;
11032   priv->clip.width = width;
11033   priv->clip.height = height;
11034
11035   priv->has_clip = TRUE;
11036
11037   clutter_actor_queue_redraw (self);
11038
11039   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11040   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
11041 }
11042
11043 /**
11044  * clutter_actor_remove_clip:
11045  * @self: A #ClutterActor
11046  *
11047  * Removes clip area from @self.
11048  */
11049 void
11050 clutter_actor_remove_clip (ClutterActor *self)
11051 {
11052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11053
11054   if (!self->priv->has_clip)
11055     return;
11056
11057   self->priv->has_clip = FALSE;
11058
11059   clutter_actor_queue_redraw (self);
11060
11061   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11062 }
11063
11064 /**
11065  * clutter_actor_has_clip:
11066  * @self: a #ClutterActor
11067  *
11068  * Determines whether the actor has a clip area set or not.
11069  *
11070  * Return value: %TRUE if the actor has a clip area set.
11071  *
11072  * Since: 0.1.1
11073  */
11074 gboolean
11075 clutter_actor_has_clip (ClutterActor *self)
11076 {
11077   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11078
11079   return self->priv->has_clip;
11080 }
11081
11082 /**
11083  * clutter_actor_get_clip:
11084  * @self: a #ClutterActor
11085  * @xoff: (out) (allow-none): return location for the X offset of
11086  *   the clip rectangle, or %NULL
11087  * @yoff: (out) (allow-none): return location for the Y offset of
11088  *   the clip rectangle, or %NULL
11089  * @width: (out) (allow-none): return location for the width of
11090  *   the clip rectangle, or %NULL
11091  * @height: (out) (allow-none): return location for the height of
11092  *   the clip rectangle, or %NULL
11093  *
11094  * Gets the clip area for @self, if any is set
11095  *
11096  * Since: 0.6
11097  */
11098 void
11099 clutter_actor_get_clip (ClutterActor *self,
11100                         gfloat       *xoff,
11101                         gfloat       *yoff,
11102                         gfloat       *width,
11103                         gfloat       *height)
11104 {
11105   ClutterActorPrivate *priv;
11106
11107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11108
11109   priv = self->priv;
11110
11111   if (!priv->has_clip)
11112     return;
11113
11114   if (xoff != NULL)
11115     *xoff = priv->clip.x;
11116
11117   if (yoff != NULL)
11118     *yoff = priv->clip.y;
11119
11120   if (width != NULL)
11121     *width = priv->clip.width;
11122
11123   if (height != NULL)
11124     *height = priv->clip.height;
11125 }
11126
11127 /**
11128  * clutter_actor_get_children:
11129  * @self: a #ClutterActor
11130  *
11131  * Retrieves the list of children of @self.
11132  *
11133  * Return value: (transfer container) (element-type ClutterActor): A newly
11134  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11135  *   done.
11136  *
11137  * Since: 1.10
11138  */
11139 GList *
11140 clutter_actor_get_children (ClutterActor *self)
11141 {
11142   ClutterActor *iter;
11143   GList *res;
11144
11145   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11146
11147   /* we walk the list backward so that we can use prepend(),
11148    * which is O(1)
11149    */
11150   for (iter = self->priv->last_child, res = NULL;
11151        iter != NULL;
11152        iter = iter->priv->prev_sibling)
11153     {
11154       res = g_list_prepend (res, iter);
11155     }
11156
11157   return res;
11158 }
11159
11160 /*< private >
11161  * insert_child_at_depth:
11162  * @self: a #ClutterActor
11163  * @child: a #ClutterActor
11164  *
11165  * Inserts @child inside the list of children held by @self, using
11166  * the depth as the insertion criteria.
11167  *
11168  * This sadly makes the insertion not O(1), but we can keep the
11169  * list sorted so that the painters algorithm we use for painting
11170  * the children will work correctly.
11171  */
11172 static void
11173 insert_child_at_depth (ClutterActor *self,
11174                        ClutterActor *child,
11175                        gpointer      dummy G_GNUC_UNUSED)
11176 {
11177   ClutterActor *iter;
11178   float child_depth;
11179
11180   child->priv->parent = self;
11181
11182   child_depth =
11183     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11184
11185   /* special-case the first child */
11186   if (self->priv->n_children == 0)
11187     {
11188       self->priv->first_child = child;
11189       self->priv->last_child = child;
11190
11191       child->priv->next_sibling = NULL;
11192       child->priv->prev_sibling = NULL;
11193
11194       return;
11195     }
11196
11197   /* Find the right place to insert the child so that it will still be
11198      sorted and the child will be after all of the actors at the same
11199      dept */
11200   for (iter = self->priv->first_child;
11201        iter != NULL;
11202        iter = iter->priv->next_sibling)
11203     {
11204       float iter_depth;
11205
11206       iter_depth =
11207         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11208
11209       if (iter_depth > child_depth)
11210         break;
11211     }
11212
11213   if (iter != NULL)
11214     {
11215       ClutterActor *tmp = iter->priv->prev_sibling;
11216
11217       if (tmp != NULL)
11218         tmp->priv->next_sibling = child;
11219
11220       /* Insert the node before the found one */
11221       child->priv->prev_sibling = iter->priv->prev_sibling;
11222       child->priv->next_sibling = iter;
11223       iter->priv->prev_sibling = child;
11224     }
11225   else
11226     {
11227       ClutterActor *tmp = self->priv->last_child;
11228
11229       if (tmp != NULL)
11230         tmp->priv->next_sibling = child;
11231
11232       /* insert the node at the end of the list */
11233       child->priv->prev_sibling = self->priv->last_child;
11234       child->priv->next_sibling = NULL;
11235     }
11236
11237   if (child->priv->prev_sibling == NULL)
11238     self->priv->first_child = child;
11239
11240   if (child->priv->next_sibling == NULL)
11241     self->priv->last_child = child;
11242 }
11243
11244 static void
11245 insert_child_at_index (ClutterActor *self,
11246                        ClutterActor *child,
11247                        gpointer      data_)
11248 {
11249   gint index_ = GPOINTER_TO_INT (data_);
11250
11251   child->priv->parent = self;
11252
11253   if (index_ == 0)
11254     {
11255       ClutterActor *tmp = self->priv->first_child;
11256
11257       if (tmp != NULL)
11258         tmp->priv->prev_sibling = child;
11259
11260       child->priv->prev_sibling = NULL;
11261       child->priv->next_sibling = tmp;
11262     }
11263   else if (index_ < 0 || index_ >= self->priv->n_children)
11264     {
11265       ClutterActor *tmp = self->priv->last_child;
11266
11267       if (tmp != NULL)
11268         tmp->priv->next_sibling = child;
11269
11270       child->priv->prev_sibling = tmp;
11271       child->priv->next_sibling = NULL;
11272     }
11273   else
11274     {
11275       ClutterActor *iter;
11276       int i;
11277
11278       for (iter = self->priv->first_child, i = 0;
11279            iter != NULL;
11280            iter = iter->priv->next_sibling, i += 1)
11281         {
11282           if (index_ == i)
11283             {
11284               ClutterActor *tmp = iter->priv->prev_sibling;
11285
11286               child->priv->prev_sibling = tmp;
11287               child->priv->next_sibling = iter;
11288
11289               iter->priv->prev_sibling = child;
11290
11291               if (tmp != NULL)
11292                 tmp->priv->next_sibling = child;
11293
11294               break;
11295             }
11296         }
11297     }
11298
11299   if (child->priv->prev_sibling == NULL)
11300     self->priv->first_child = child;
11301
11302   if (child->priv->next_sibling == NULL)
11303     self->priv->last_child = child;
11304 }
11305
11306 static void
11307 insert_child_above (ClutterActor *self,
11308                     ClutterActor *child,
11309                     gpointer      data)
11310 {
11311   ClutterActor *sibling = data;
11312
11313   child->priv->parent = self;
11314
11315   if (sibling == NULL)
11316     sibling = self->priv->last_child;
11317
11318   child->priv->prev_sibling = sibling;
11319
11320   if (sibling != NULL)
11321     {
11322       ClutterActor *tmp = sibling->priv->next_sibling;
11323
11324       child->priv->next_sibling = tmp;
11325
11326       if (tmp != NULL)
11327         tmp->priv->prev_sibling = child;
11328
11329       sibling->priv->next_sibling = child;
11330     }
11331   else
11332     child->priv->next_sibling = NULL;
11333
11334   if (child->priv->prev_sibling == NULL)
11335     self->priv->first_child = child;
11336
11337   if (child->priv->next_sibling == NULL)
11338     self->priv->last_child = child;
11339 }
11340
11341 static void
11342 insert_child_below (ClutterActor *self,
11343                     ClutterActor *child,
11344                     gpointer      data)
11345 {
11346   ClutterActor *sibling = data;
11347
11348   child->priv->parent = self;
11349
11350   if (sibling == NULL)
11351     sibling = self->priv->first_child;
11352
11353   child->priv->next_sibling = sibling;
11354
11355   if (sibling != NULL)
11356     {
11357       ClutterActor *tmp = sibling->priv->prev_sibling;
11358
11359       child->priv->prev_sibling = tmp;
11360
11361       if (tmp != NULL)
11362         tmp->priv->next_sibling = child;
11363
11364       sibling->priv->prev_sibling = child;
11365     }
11366   else
11367     child->priv->prev_sibling = NULL;
11368
11369   if (child->priv->prev_sibling == NULL)
11370     self->priv->first_child = child;
11371
11372   if (child->priv->next_sibling == NULL)
11373     self->priv->last_child = child;
11374 }
11375
11376 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11377                                            ClutterActor *child,
11378                                            gpointer      data);
11379
11380 typedef enum {
11381   ADD_CHILD_CREATE_META        = 1 << 0,
11382   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11383   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11384   ADD_CHILD_CHECK_STATE        = 1 << 3,
11385   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11386   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11387
11388   /* default flags for public API */
11389   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11390                                ADD_CHILD_EMIT_PARENT_SET |
11391                                ADD_CHILD_EMIT_ACTOR_ADDED |
11392                                ADD_CHILD_CHECK_STATE |
11393                                ADD_CHILD_NOTIFY_FIRST_LAST |
11394                                ADD_CHILD_SHOW_ON_SET_PARENT,
11395
11396   /* flags for legacy/deprecated API */
11397   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11398                                ADD_CHILD_CHECK_STATE |
11399                                ADD_CHILD_NOTIFY_FIRST_LAST |
11400                                ADD_CHILD_SHOW_ON_SET_PARENT
11401 } ClutterActorAddChildFlags;
11402
11403 /*< private >
11404  * clutter_actor_add_child_internal:
11405  * @self: a #ClutterActor
11406  * @child: a #ClutterActor
11407  * @flags: control flags for actions
11408  * @add_func: delegate function
11409  * @data: (closure): data to pass to @add_func
11410  *
11411  * Adds @child to the list of children of @self.
11412  *
11413  * The actual insertion inside the list is delegated to @add_func: this
11414  * function will just set up the state, perform basic checks, and emit
11415  * signals.
11416  *
11417  * The @flags argument is used to perform additional operations.
11418  */
11419 static inline void
11420 clutter_actor_add_child_internal (ClutterActor              *self,
11421                                   ClutterActor              *child,
11422                                   ClutterActorAddChildFlags  flags,
11423                                   ClutterActorAddChildFunc   add_func,
11424                                   gpointer                   data)
11425 {
11426   ClutterTextDirection text_dir;
11427   gboolean create_meta;
11428   gboolean emit_parent_set, emit_actor_added;
11429   gboolean check_state;
11430   gboolean notify_first_last;
11431   gboolean show_on_set_parent;
11432   ClutterActor *old_first_child, *old_last_child;
11433
11434   if (child->priv->parent != NULL)
11435     {
11436       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11437                  "use clutter_actor_remove_child() first.",
11438                  _clutter_actor_get_debug_name (child),
11439                  _clutter_actor_get_debug_name (child->priv->parent));
11440       return;
11441     }
11442
11443   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11444     {
11445       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11446                  "a child of another actor.",
11447                  _clutter_actor_get_debug_name (child));
11448       return;
11449     }
11450
11451 #if 0
11452   /* XXX - this check disallows calling methods that change the stacking
11453    * order within the destruction sequence, by triggering a critical
11454    * warning first, and leaving the actor in an undefined state, which
11455    * then ends up being caught by an assertion.
11456    *
11457    * the reproducible sequence is:
11458    *
11459    *   - actor gets destroyed;
11460    *   - another actor, linked to the first, will try to change the
11461    *     stacking order of the first actor;
11462    *   - changing the stacking order is a composite operation composed
11463    *     by the following steps:
11464    *     1. ref() the child;
11465    *     2. remove_child_internal(), which removes the reference;
11466    *     3. add_child_internal(), which adds a reference;
11467    *   - the state of the actor is not changed between (2) and (3), as
11468    *     it could be an expensive recomputation;
11469    *   - if (3) bails out, then the actor is in an undefined state, but
11470    *     still alive;
11471    *   - the destruction sequence terminates, but the actor is unparented
11472    *     while its state indicates being parented instead.
11473    *   - assertion failure.
11474    *
11475    * the obvious fix would be to decompose each set_child_*_sibling()
11476    * method into proper remove_child()/add_child(), with state validation;
11477    * this may cause excessive work, though, and trigger a cascade of other
11478    * bugs in code that assumes that a change in the stacking order is an
11479    * atomic operation.
11480    *
11481    * another potential fix is to just remove this check here, and let
11482    * code doing stacking order changes inside the destruction sequence
11483    * of an actor continue doing the work.
11484    *
11485    * the third fix is to silently bail out early from every
11486    * set_child_*_sibling() and set_child_at_index() method, and avoid
11487    * doing work.
11488    *
11489    * I have a preference for the second solution, since it involves the
11490    * least amount of work, and the least amount of code duplication.
11491    *
11492    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11493    */
11494   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11495     {
11496       g_warning ("The actor '%s' is currently being destroyed, and "
11497                  "cannot be added as a child of another actor.",
11498                  _clutter_actor_get_debug_name (child));
11499       return;
11500     }
11501 #endif
11502
11503   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11504   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11505   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11506   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11507   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11508   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11509
11510   old_first_child = self->priv->first_child;
11511   old_last_child = self->priv->last_child;
11512
11513   g_object_freeze_notify (G_OBJECT (self));
11514
11515   if (create_meta)
11516     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11517
11518   g_object_ref_sink (child);
11519   child->priv->parent = NULL;
11520   child->priv->next_sibling = NULL;
11521   child->priv->prev_sibling = NULL;
11522
11523   /* delegate the actual insertion */
11524   add_func (self, child, data);
11525
11526   g_assert (child->priv->parent == self);
11527
11528   self->priv->n_children += 1;
11529
11530   self->priv->age += 1;
11531
11532   /* if push_internal() has been called then we automatically set
11533    * the flag on the actor
11534    */
11535   if (self->priv->internal_child)
11536     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11537
11538   /* children may cause their parent to expand, if they are set
11539    * to expand; if a child is not expanded then it cannot change
11540    * its parent's state. any further change later on will queue
11541    * an expand state check.
11542    *
11543    * this check, with the initial state of the needs_compute_expand
11544    * flag set to FALSE, should avoid recomputing the expand flags
11545    * state while building the actor tree.
11546    */
11547   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11548       (child->priv->needs_compute_expand ||
11549        child->priv->needs_x_expand ||
11550        child->priv->needs_y_expand))
11551     {
11552       clutter_actor_queue_compute_expand (self);
11553     }
11554
11555   /* clutter_actor_reparent() will emit ::parent-set for us */
11556   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11557     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11558
11559   if (check_state)
11560     {
11561       /* If parent is mapped or realized, we need to also be mapped or
11562        * realized once we're inside the parent.
11563        */
11564       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11565
11566       /* propagate the parent's text direction to the child */
11567       text_dir = clutter_actor_get_text_direction (self);
11568       clutter_actor_set_text_direction (child, text_dir);
11569     }
11570
11571   if (show_on_set_parent && child->priv->show_on_set_parent)
11572     clutter_actor_show (child);
11573
11574   if (CLUTTER_ACTOR_IS_MAPPED (child))
11575     clutter_actor_queue_redraw (child);
11576
11577   /* maintain the invariant that if an actor needs layout,
11578    * its parents do as well
11579    */
11580   if (child->priv->needs_width_request ||
11581       child->priv->needs_height_request ||
11582       child->priv->needs_allocation)
11583     {
11584       /* we work around the short-circuiting we do
11585        * in clutter_actor_queue_relayout() since we
11586        * want to force a relayout
11587        */
11588       child->priv->needs_width_request = TRUE;
11589       child->priv->needs_height_request = TRUE;
11590       child->priv->needs_allocation = TRUE;
11591
11592       clutter_actor_queue_relayout (child->priv->parent);
11593     }
11594
11595   if (emit_actor_added)
11596     g_signal_emit_by_name (self, "actor-added", child);
11597
11598   if (notify_first_last)
11599     {
11600       if (old_first_child != self->priv->first_child)
11601         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11602
11603       if (old_last_child != self->priv->last_child)
11604         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11605     }
11606
11607   g_object_thaw_notify (G_OBJECT (self));
11608 }
11609
11610 /**
11611  * clutter_actor_add_child:
11612  * @self: a #ClutterActor
11613  * @child: a #ClutterActor
11614  *
11615  * Adds @child to the children of @self.
11616  *
11617  * This function will acquire a reference on @child that will only
11618  * be released when calling clutter_actor_remove_child().
11619  *
11620  * This function will take into consideration the #ClutterActor:depth
11621  * of @child, and will keep the list of children sorted.
11622  *
11623  * This function will emit the #ClutterContainer::actor-added signal
11624  * on @self.
11625  *
11626  * Since: 1.10
11627  */
11628 void
11629 clutter_actor_add_child (ClutterActor *self,
11630                          ClutterActor *child)
11631 {
11632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11633   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11634   g_return_if_fail (self != child);
11635   g_return_if_fail (child->priv->parent == NULL);
11636
11637   clutter_actor_add_child_internal (self, child,
11638                                     ADD_CHILD_DEFAULT_FLAGS,
11639                                     insert_child_at_depth,
11640                                     NULL);
11641 }
11642
11643 /**
11644  * clutter_actor_insert_child_at_index:
11645  * @self: a #ClutterActor
11646  * @child: a #ClutterActor
11647  * @index_: the index
11648  *
11649  * Inserts @child into the list of children of @self, using the
11650  * given @index_. If @index_ is greater than the number of children
11651  * in @self, or is less than 0, then the new child is added at the end.
11652  *
11653  * This function will acquire a reference on @child that will only
11654  * be released when calling clutter_actor_remove_child().
11655  *
11656  * This function will not take into consideration the #ClutterActor:depth
11657  * of @child.
11658  *
11659  * This function will emit the #ClutterContainer::actor-added signal
11660  * on @self.
11661  *
11662  * Since: 1.10
11663  */
11664 void
11665 clutter_actor_insert_child_at_index (ClutterActor *self,
11666                                      ClutterActor *child,
11667                                      gint          index_)
11668 {
11669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11670   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11671   g_return_if_fail (self != child);
11672   g_return_if_fail (child->priv->parent == NULL);
11673
11674   clutter_actor_add_child_internal (self, child,
11675                                     ADD_CHILD_DEFAULT_FLAGS,
11676                                     insert_child_at_index,
11677                                     GINT_TO_POINTER (index_));
11678 }
11679
11680 /**
11681  * clutter_actor_insert_child_above:
11682  * @self: a #ClutterActor
11683  * @child: a #ClutterActor
11684  * @sibling: (allow-none): a child of @self, or %NULL
11685  *
11686  * Inserts @child into the list of children of @self, above another
11687  * child of @self or, if @sibling is %NULL, above all the children
11688  * of @self.
11689  *
11690  * This function will acquire a reference on @child that will only
11691  * be released when calling clutter_actor_remove_child().
11692  *
11693  * This function will not take into consideration the #ClutterActor:depth
11694  * of @child.
11695  *
11696  * This function will emit the #ClutterContainer::actor-added signal
11697  * on @self.
11698  *
11699  * Since: 1.10
11700  */
11701 void
11702 clutter_actor_insert_child_above (ClutterActor *self,
11703                                   ClutterActor *child,
11704                                   ClutterActor *sibling)
11705 {
11706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11707   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11708   g_return_if_fail (self != child);
11709   g_return_if_fail (child != sibling);
11710   g_return_if_fail (child->priv->parent == NULL);
11711   g_return_if_fail (sibling == NULL ||
11712                     (CLUTTER_IS_ACTOR (sibling) &&
11713                      sibling->priv->parent == self));
11714
11715   clutter_actor_add_child_internal (self, child,
11716                                     ADD_CHILD_DEFAULT_FLAGS,
11717                                     insert_child_above,
11718                                     sibling);
11719 }
11720
11721 /**
11722  * clutter_actor_insert_child_below:
11723  * @self: a #ClutterActor
11724  * @child: a #ClutterActor
11725  * @sibling: (allow-none): a child of @self, or %NULL
11726  *
11727  * Inserts @child into the list of children of @self, below another
11728  * child of @self or, if @sibling is %NULL, below all the children
11729  * of @self.
11730  *
11731  * This function will acquire a reference on @child that will only
11732  * be released when calling clutter_actor_remove_child().
11733  *
11734  * This function will not take into consideration the #ClutterActor:depth
11735  * of @child.
11736  *
11737  * This function will emit the #ClutterContainer::actor-added signal
11738  * on @self.
11739  *
11740  * Since: 1.10
11741  */
11742 void
11743 clutter_actor_insert_child_below (ClutterActor *self,
11744                                   ClutterActor *child,
11745                                   ClutterActor *sibling)
11746 {
11747   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11748   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11749   g_return_if_fail (self != child);
11750   g_return_if_fail (child != sibling);
11751   g_return_if_fail (child->priv->parent == NULL);
11752   g_return_if_fail (sibling == NULL ||
11753                     (CLUTTER_IS_ACTOR (sibling) &&
11754                      sibling->priv->parent == self));
11755
11756   clutter_actor_add_child_internal (self, child,
11757                                     ADD_CHILD_DEFAULT_FLAGS,
11758                                     insert_child_below,
11759                                     sibling);
11760 }
11761
11762 /**
11763  * clutter_actor_set_parent:
11764  * @self: A #ClutterActor
11765  * @parent: A new #ClutterActor parent
11766  *
11767  * Sets the parent of @self to @parent.
11768  *
11769  * This function will result in @parent acquiring a reference on @self,
11770  * eventually by sinking its floating reference first. The reference
11771  * will be released by clutter_actor_unparent().
11772  *
11773  * This function should only be called by legacy #ClutterActor<!-- -->s
11774  * implementing the #ClutterContainer interface.
11775  *
11776  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11777  */
11778 void
11779 clutter_actor_set_parent (ClutterActor *self,
11780                           ClutterActor *parent)
11781 {
11782   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11783   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11784   g_return_if_fail (self != parent);
11785   g_return_if_fail (self->priv->parent == NULL);
11786
11787   /* as this function will be called inside ClutterContainer::add
11788    * implementations or when building up a composite actor, we have
11789    * to preserve the old behaviour, and not create child meta or
11790    * emit the ::actor-added signal, to avoid recursion or double
11791    * emissions
11792    */
11793   clutter_actor_add_child_internal (parent, self,
11794                                     ADD_CHILD_LEGACY_FLAGS,
11795                                     insert_child_at_depth,
11796                                     NULL);
11797 }
11798
11799 /**
11800  * clutter_actor_get_parent:
11801  * @self: A #ClutterActor
11802  *
11803  * Retrieves the parent of @self.
11804  *
11805  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11806  *  if no parent is set
11807  */
11808 ClutterActor *
11809 clutter_actor_get_parent (ClutterActor *self)
11810 {
11811   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11812
11813   return self->priv->parent;
11814 }
11815
11816 /**
11817  * clutter_actor_get_paint_visibility:
11818  * @self: A #ClutterActor
11819  *
11820  * Retrieves the 'paint' visibility of an actor recursively checking for non
11821  * visible parents.
11822  *
11823  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11824  *
11825  * Return Value: %TRUE if the actor is visibile and will be painted.
11826  *
11827  * Since: 0.8.4
11828  */
11829 gboolean
11830 clutter_actor_get_paint_visibility (ClutterActor *actor)
11831 {
11832   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11833
11834   return CLUTTER_ACTOR_IS_MAPPED (actor);
11835 }
11836
11837 /**
11838  * clutter_actor_remove_child:
11839  * @self: a #ClutterActor
11840  * @child: a #ClutterActor
11841  *
11842  * Removes @child from the children of @self.
11843  *
11844  * This function will release the reference added by
11845  * clutter_actor_add_child(), so if you want to keep using @child
11846  * you will have to acquire a referenced on it before calling this
11847  * function.
11848  *
11849  * This function will emit the #ClutterContainer::actor-removed
11850  * signal on @self.
11851  *
11852  * Since: 1.10
11853  */
11854 void
11855 clutter_actor_remove_child (ClutterActor *self,
11856                             ClutterActor *child)
11857 {
11858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11859   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11860   g_return_if_fail (self != child);
11861   g_return_if_fail (child->priv->parent != NULL);
11862   g_return_if_fail (child->priv->parent == self);
11863
11864   clutter_actor_remove_child_internal (self, child,
11865                                        REMOVE_CHILD_DEFAULT_FLAGS);
11866 }
11867
11868 /**
11869  * clutter_actor_remove_all_children:
11870  * @self: a #ClutterActor
11871  *
11872  * Removes all children of @self.
11873  *
11874  * This function releases the reference added by inserting a child actor
11875  * in the list of children of @self.
11876  *
11877  * If the reference count of a child drops to zero, the child will be
11878  * destroyed. If you want to ensure the destruction of all the children
11879  * of @self, use clutter_actor_destroy_all_children().
11880  *
11881  * Since: 1.10
11882  */
11883 void
11884 clutter_actor_remove_all_children (ClutterActor *self)
11885 {
11886   ClutterActorIter iter;
11887
11888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11889
11890   if (self->priv->n_children == 0)
11891     return;
11892
11893   g_object_freeze_notify (G_OBJECT (self));
11894
11895   clutter_actor_iter_init (&iter, self);
11896   while (clutter_actor_iter_next (&iter, NULL))
11897     clutter_actor_iter_remove (&iter);
11898
11899   g_object_thaw_notify (G_OBJECT (self));
11900
11901   /* sanity check */
11902   g_assert (self->priv->first_child == NULL);
11903   g_assert (self->priv->last_child == NULL);
11904   g_assert (self->priv->n_children == 0);
11905 }
11906
11907 /**
11908  * clutter_actor_destroy_all_children:
11909  * @self: a #ClutterActor
11910  *
11911  * Destroys all children of @self.
11912  *
11913  * This function releases the reference added by inserting a child
11914  * actor in the list of children of @self, and ensures that the
11915  * #ClutterActor::destroy signal is emitted on each child of the
11916  * actor.
11917  *
11918  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11919  * when its reference count drops to 0; the default handler of the
11920  * #ClutterActor::destroy signal will destroy all the children of an
11921  * actor. This function ensures that all children are destroyed, instead
11922  * of just removed from @self, unlike clutter_actor_remove_all_children()
11923  * which will merely release the reference and remove each child.
11924  *
11925  * Unless you acquired an additional reference on each child of @self
11926  * prior to calling clutter_actor_remove_all_children() and want to reuse
11927  * the actors, you should use clutter_actor_destroy_all_children() in
11928  * order to make sure that children are destroyed and signal handlers
11929  * are disconnected even in cases where circular references prevent this
11930  * from automatically happening through reference counting alone.
11931  *
11932  * Since: 1.10
11933  */
11934 void
11935 clutter_actor_destroy_all_children (ClutterActor *self)
11936 {
11937   ClutterActorIter iter;
11938
11939   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11940
11941   if (self->priv->n_children == 0)
11942     return;
11943
11944   g_object_freeze_notify (G_OBJECT (self));
11945
11946   clutter_actor_iter_init (&iter, self);
11947   while (clutter_actor_iter_next (&iter, NULL))
11948     clutter_actor_iter_destroy (&iter);
11949
11950   g_object_thaw_notify (G_OBJECT (self));
11951
11952   /* sanity check */
11953   g_assert (self->priv->first_child == NULL);
11954   g_assert (self->priv->last_child == NULL);
11955   g_assert (self->priv->n_children == 0);
11956 }
11957
11958 typedef struct _InsertBetweenData {
11959   ClutterActor *prev_sibling;
11960   ClutterActor *next_sibling;
11961 } InsertBetweenData;
11962
11963 static void
11964 insert_child_between (ClutterActor *self,
11965                       ClutterActor *child,
11966                       gpointer      data_)
11967 {
11968   InsertBetweenData *data = data_;
11969   ClutterActor *prev_sibling = data->prev_sibling;
11970   ClutterActor *next_sibling = data->next_sibling;
11971
11972   child->priv->parent = self;
11973   child->priv->prev_sibling = prev_sibling;
11974   child->priv->next_sibling = next_sibling;
11975
11976   if (prev_sibling != NULL)
11977     prev_sibling->priv->next_sibling = child;
11978
11979   if (next_sibling != NULL)
11980     next_sibling->priv->prev_sibling = child;
11981
11982   if (child->priv->prev_sibling == NULL)
11983     self->priv->first_child = child;
11984
11985   if (child->priv->next_sibling == NULL)
11986     self->priv->last_child = child;
11987 }
11988
11989 /**
11990  * clutter_actor_replace_child:
11991  * @self: a #ClutterActor
11992  * @old_child: the child of @self to replace
11993  * @new_child: the #ClutterActor to replace @old_child
11994  *
11995  * Replaces @old_child with @new_child in the list of children of @self.
11996  *
11997  * Since: 1.10
11998  */
11999 void
12000 clutter_actor_replace_child (ClutterActor *self,
12001                              ClutterActor *old_child,
12002                              ClutterActor *new_child)
12003 {
12004   ClutterActor *prev_sibling, *next_sibling;
12005   InsertBetweenData clos;
12006
12007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12008   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
12009   g_return_if_fail (old_child->priv->parent == self);
12010   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
12011   g_return_if_fail (old_child != new_child);
12012   g_return_if_fail (new_child != self);
12013   g_return_if_fail (new_child->priv->parent == NULL);
12014
12015   prev_sibling = old_child->priv->prev_sibling;
12016   next_sibling = old_child->priv->next_sibling;
12017   clutter_actor_remove_child_internal (self, old_child,
12018                                        REMOVE_CHILD_DEFAULT_FLAGS);
12019
12020   clos.prev_sibling = prev_sibling;
12021   clos.next_sibling = next_sibling;
12022   clutter_actor_add_child_internal (self, new_child,
12023                                     ADD_CHILD_DEFAULT_FLAGS,
12024                                     insert_child_between,
12025                                     &clos);
12026 }
12027
12028 /**
12029  * clutter_actor_unparent:
12030  * @self: a #ClutterActor
12031  *
12032  * Removes the parent of @self.
12033  *
12034  * This will cause the parent of @self to release the reference
12035  * acquired when calling clutter_actor_set_parent(), so if you
12036  * want to keep @self you will have to acquire a reference of
12037  * your own, through g_object_ref().
12038  *
12039  * This function should only be called by legacy #ClutterActor<!-- -->s
12040  * implementing the #ClutterContainer interface.
12041  *
12042  * Since: 0.1.1
12043  *
12044  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12045  */
12046 void
12047 clutter_actor_unparent (ClutterActor *self)
12048 {
12049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12050
12051   if (self->priv->parent == NULL)
12052     return;
12053
12054   clutter_actor_remove_child_internal (self->priv->parent, self,
12055                                        REMOVE_CHILD_LEGACY_FLAGS);
12056 }
12057
12058 /**
12059  * clutter_actor_reparent:
12060  * @self: a #ClutterActor
12061  * @new_parent: the new #ClutterActor parent
12062  *
12063  * Resets the parent actor of @self.
12064  *
12065  * This function is logically equivalent to calling clutter_actor_unparent()
12066  * and clutter_actor_set_parent(), but more efficiently implemented, as it
12067  * ensures the child is not finalized when unparented, and emits the
12068  * #ClutterActor::parent-set signal only once.
12069  *
12070  * In reality, calling this function is less useful than it sounds, as some
12071  * application code may rely on changes in the intermediate state between
12072  * removal and addition of the actor from its old parent to the @new_parent.
12073  * Thus, it is strongly encouraged to avoid using this function in application
12074  * code.
12075  *
12076  * Since: 0.2
12077  *
12078  * Deprecated: 1.10: Use clutter_actor_remove_child() and
12079  *   clutter_actor_add_child() instead; remember to take a reference on
12080  *   the actor being removed before calling clutter_actor_remove_child()
12081  *   to avoid the reference count dropping to zero and the actor being
12082  *   destroyed.
12083  */
12084 void
12085 clutter_actor_reparent (ClutterActor *self,
12086                         ClutterActor *new_parent)
12087 {
12088   ClutterActorPrivate *priv;
12089
12090   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12091   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12092   g_return_if_fail (self != new_parent);
12093
12094   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12095     {
12096       g_warning ("Cannot set a parent on a toplevel actor");
12097       return;
12098     }
12099
12100   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12101     {
12102       g_warning ("Cannot set a parent currently being destroyed");
12103       return;
12104     }
12105
12106   priv = self->priv;
12107
12108   if (priv->parent != new_parent)
12109     {
12110       ClutterActor *old_parent;
12111
12112       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12113
12114       old_parent = priv->parent;
12115
12116       g_object_ref (self);
12117
12118       if (old_parent != NULL)
12119         {
12120          /* go through the Container implementation if this is a regular
12121           * child and not an internal one
12122           */
12123          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12124            {
12125              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12126
12127              /* this will have to call unparent() */
12128              clutter_container_remove_actor (parent, self);
12129            }
12130          else
12131            clutter_actor_remove_child_internal (old_parent, self,
12132                                                 REMOVE_CHILD_LEGACY_FLAGS);
12133         }
12134
12135       /* Note, will call set_parent() */
12136       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12137         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12138       else
12139         clutter_actor_add_child_internal (new_parent, self,
12140                                           ADD_CHILD_LEGACY_FLAGS,
12141                                           insert_child_at_depth,
12142                                           NULL);
12143
12144       /* we emit the ::parent-set signal once */
12145       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12146
12147       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12148
12149       /* the IN_REPARENT flag suspends state updates */
12150       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12151
12152       g_object_unref (self);
12153    }
12154 }
12155
12156 /**
12157  * clutter_actor_contains:
12158  * @self: A #ClutterActor
12159  * @descendant: A #ClutterActor, possibly contained in @self
12160  *
12161  * Determines if @descendant is contained inside @self (either as an
12162  * immediate child, or as a deeper descendant). If @self and
12163  * @descendant point to the same actor then it will also return %TRUE.
12164  *
12165  * Return value: whether @descendent is contained within @self
12166  *
12167  * Since: 1.4
12168  */
12169 gboolean
12170 clutter_actor_contains (ClutterActor *self,
12171                         ClutterActor *descendant)
12172 {
12173   ClutterActor *actor;
12174
12175   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12176   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12177
12178   for (actor = descendant; actor; actor = actor->priv->parent)
12179     if (actor == self)
12180       return TRUE;
12181
12182   return FALSE;
12183 }
12184
12185 /**
12186  * clutter_actor_set_child_above_sibling:
12187  * @self: a #ClutterActor
12188  * @child: a #ClutterActor child of @self
12189  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12190  *
12191  * Sets @child to be above @sibling in the list of children of @self.
12192  *
12193  * If @sibling is %NULL, @child will be the new last child of @self.
12194  *
12195  * This function is logically equivalent to removing @child and using
12196  * clutter_actor_insert_child_above(), but it will not emit signals
12197  * or change state on @child.
12198  *
12199  * Since: 1.10
12200  */
12201 void
12202 clutter_actor_set_child_above_sibling (ClutterActor *self,
12203                                        ClutterActor *child,
12204                                        ClutterActor *sibling)
12205 {
12206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12207   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12208   g_return_if_fail (child->priv->parent == self);
12209   g_return_if_fail (child != sibling);
12210   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12211
12212   if (sibling != NULL)
12213     g_return_if_fail (sibling->priv->parent == self);
12214
12215   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12216       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12217       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12218     return;
12219
12220   /* we don't want to change the state of child, or emit signals, or
12221    * regenerate ChildMeta instances here, but we still want to follow
12222    * the correct sequence of steps encoded in remove_child() and
12223    * add_child(), so that correctness is ensured, and we only go
12224    * through one known code path.
12225    */
12226   g_object_ref (child);
12227   clutter_actor_remove_child_internal (self, child, 0);
12228   clutter_actor_add_child_internal (self, child,
12229                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12230                                     insert_child_above,
12231                                     sibling);
12232
12233   clutter_actor_queue_relayout (self);
12234 }
12235
12236 /**
12237  * clutter_actor_set_child_below_sibling:
12238  * @self: a #ClutterActor
12239  * @child: a #ClutterActor child of @self
12240  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12241  *
12242  * Sets @child to be below @sibling in the list of children of @self.
12243  *
12244  * If @sibling is %NULL, @child will be the new first child of @self.
12245  *
12246  * This function is logically equivalent to removing @self and using
12247  * clutter_actor_insert_child_below(), but it will not emit signals
12248  * or change state on @child.
12249  *
12250  * Since: 1.10
12251  */
12252 void
12253 clutter_actor_set_child_below_sibling (ClutterActor *self,
12254                                        ClutterActor *child,
12255                                        ClutterActor *sibling)
12256 {
12257   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12258   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12259   g_return_if_fail (child->priv->parent == self);
12260   g_return_if_fail (child != sibling);
12261   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12262
12263   if (sibling != NULL)
12264     g_return_if_fail (sibling->priv->parent == self);
12265
12266   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12267       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12268       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12269     return;
12270
12271   /* see the comment in set_child_above_sibling() */
12272   g_object_ref (child);
12273   clutter_actor_remove_child_internal (self, child, 0);
12274   clutter_actor_add_child_internal (self, child,
12275                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12276                                     insert_child_below,
12277                                     sibling);
12278
12279   clutter_actor_queue_relayout (self);
12280 }
12281
12282 /**
12283  * clutter_actor_set_child_at_index:
12284  * @self: a #ClutterActor
12285  * @child: a #ClutterActor child of @self
12286  * @index_: the new index for @child
12287  *
12288  * Changes the index of @child in the list of children of @self.
12289  *
12290  * This function is logically equivalent to removing @child and
12291  * calling clutter_actor_insert_child_at_index(), but it will not
12292  * emit signals or change state on @child.
12293  *
12294  * Since: 1.10
12295  */
12296 void
12297 clutter_actor_set_child_at_index (ClutterActor *self,
12298                                   ClutterActor *child,
12299                                   gint          index_)
12300 {
12301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12302   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12303   g_return_if_fail (child->priv->parent == self);
12304   g_return_if_fail (index_ <= self->priv->n_children);
12305
12306   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12307       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12308     return;
12309
12310   g_object_ref (child);
12311   clutter_actor_remove_child_internal (self, child, 0);
12312   clutter_actor_add_child_internal (self, child,
12313                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12314                                     insert_child_at_index,
12315                                     GINT_TO_POINTER (index_));
12316
12317   clutter_actor_queue_relayout (self);
12318 }
12319
12320 /**
12321  * clutter_actor_raise:
12322  * @self: A #ClutterActor
12323  * @below: (allow-none): A #ClutterActor to raise above.
12324  *
12325  * Puts @self above @below.
12326  *
12327  * Both actors must have the same parent, and the parent must implement
12328  * the #ClutterContainer interface
12329  *
12330  * This function calls clutter_container_raise_child() internally.
12331  *
12332  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12333  */
12334 void
12335 clutter_actor_raise (ClutterActor *self,
12336                      ClutterActor *below)
12337 {
12338   ClutterActor *parent;
12339
12340   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12341
12342   parent = clutter_actor_get_parent (self);
12343   if (parent == NULL)
12344     {
12345       g_warning ("%s: Actor '%s' is not inside a container",
12346                  G_STRFUNC,
12347                  _clutter_actor_get_debug_name (self));
12348       return;
12349     }
12350
12351   if (below != NULL)
12352     {
12353       if (parent != clutter_actor_get_parent (below))
12354         {
12355           g_warning ("%s Actor '%s' is not in the same container as "
12356                      "actor '%s'",
12357                      G_STRFUNC,
12358                      _clutter_actor_get_debug_name (self),
12359                      _clutter_actor_get_debug_name (below));
12360           return;
12361         }
12362     }
12363
12364   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12365 }
12366
12367 /**
12368  * clutter_actor_lower:
12369  * @self: A #ClutterActor
12370  * @above: (allow-none): A #ClutterActor to lower below
12371  *
12372  * Puts @self below @above.
12373  *
12374  * Both actors must have the same parent, and the parent must implement
12375  * the #ClutterContainer interface.
12376  *
12377  * This function calls clutter_container_lower_child() internally.
12378  *
12379  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12380  */
12381 void
12382 clutter_actor_lower (ClutterActor *self,
12383                      ClutterActor *above)
12384 {
12385   ClutterActor *parent;
12386
12387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12388
12389   parent = clutter_actor_get_parent (self);
12390   if (parent == NULL)
12391     {
12392       g_warning ("%s: Actor of type %s is not inside a container",
12393                  G_STRFUNC,
12394                  _clutter_actor_get_debug_name (self));
12395       return;
12396     }
12397
12398   if (above)
12399     {
12400       if (parent != clutter_actor_get_parent (above))
12401         {
12402           g_warning ("%s: Actor '%s' is not in the same container as "
12403                      "actor '%s'",
12404                      G_STRFUNC,
12405                      _clutter_actor_get_debug_name (self),
12406                      _clutter_actor_get_debug_name (above));
12407           return;
12408         }
12409     }
12410
12411   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12412 }
12413
12414 /**
12415  * clutter_actor_raise_top:
12416  * @self: A #ClutterActor
12417  *
12418  * Raises @self to the top.
12419  *
12420  * This function calls clutter_actor_raise() internally.
12421  *
12422  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12423  *   a %NULL sibling, instead.
12424  */
12425 void
12426 clutter_actor_raise_top (ClutterActor *self)
12427 {
12428   clutter_actor_raise (self, NULL);
12429 }
12430
12431 /**
12432  * clutter_actor_lower_bottom:
12433  * @self: A #ClutterActor
12434  *
12435  * Lowers @self to the bottom.
12436  *
12437  * This function calls clutter_actor_lower() internally.
12438  *
12439  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12440  *   a %NULL sibling, instead.
12441  */
12442 void
12443 clutter_actor_lower_bottom (ClutterActor *self)
12444 {
12445   clutter_actor_lower (self, NULL);
12446 }
12447
12448 /*
12449  * Event handling
12450  */
12451
12452 /**
12453  * clutter_actor_event:
12454  * @actor: a #ClutterActor
12455  * @event: a #ClutterEvent
12456  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12457  *
12458  * This function is used to emit an event on the main stage.
12459  * You should rarely need to use this function, except for
12460  * synthetising events.
12461  *
12462  * Return value: the return value from the signal emission: %TRUE
12463  *   if the actor handled the event, or %FALSE if the event was
12464  *   not handled
12465  *
12466  * Since: 0.6
12467  */
12468 gboolean
12469 clutter_actor_event (ClutterActor *actor,
12470                      ClutterEvent *event,
12471                      gboolean      capture)
12472 {
12473   gboolean retval = FALSE;
12474   gint signal_num = -1;
12475
12476   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12477   g_return_val_if_fail (event != NULL, FALSE);
12478
12479   g_object_ref (actor);
12480
12481   if (capture)
12482     {
12483       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12484                      event,
12485                      &retval);
12486       goto out;
12487     }
12488
12489   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12490
12491   if (!retval)
12492     {
12493       switch (event->type)
12494         {
12495         case CLUTTER_NOTHING:
12496           break;
12497         case CLUTTER_BUTTON_PRESS:
12498           signal_num = BUTTON_PRESS_EVENT;
12499           break;
12500         case CLUTTER_BUTTON_RELEASE:
12501           signal_num = BUTTON_RELEASE_EVENT;
12502           break;
12503         case CLUTTER_SCROLL:
12504           signal_num = SCROLL_EVENT;
12505           break;
12506         case CLUTTER_KEY_PRESS:
12507           signal_num = KEY_PRESS_EVENT;
12508           break;
12509         case CLUTTER_KEY_RELEASE:
12510           signal_num = KEY_RELEASE_EVENT;
12511           break;
12512         case CLUTTER_MOTION:
12513           signal_num = MOTION_EVENT;
12514           break;
12515         case CLUTTER_ENTER:
12516           signal_num = ENTER_EVENT;
12517           break;
12518         case CLUTTER_LEAVE:
12519           signal_num = LEAVE_EVENT;
12520           break;
12521         case CLUTTER_DELETE:
12522         case CLUTTER_DESTROY_NOTIFY:
12523         case CLUTTER_CLIENT_MESSAGE:
12524         default:
12525           signal_num = -1;
12526           break;
12527         }
12528
12529       if (signal_num != -1)
12530         g_signal_emit (actor, actor_signals[signal_num], 0,
12531                        event, &retval);
12532     }
12533
12534 out:
12535   g_object_unref (actor);
12536
12537   return retval;
12538 }
12539
12540 /**
12541  * clutter_actor_set_reactive:
12542  * @actor: a #ClutterActor
12543  * @reactive: whether the actor should be reactive to events
12544  *
12545  * Sets @actor as reactive. Reactive actors will receive events.
12546  *
12547  * Since: 0.6
12548  */
12549 void
12550 clutter_actor_set_reactive (ClutterActor *actor,
12551                             gboolean      reactive)
12552 {
12553   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12554
12555   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12556     return;
12557
12558   if (reactive)
12559     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12560   else
12561     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12562
12563   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12564 }
12565
12566 /**
12567  * clutter_actor_get_reactive:
12568  * @actor: a #ClutterActor
12569  *
12570  * Checks whether @actor is marked as reactive.
12571  *
12572  * Return value: %TRUE if the actor is reactive
12573  *
12574  * Since: 0.6
12575  */
12576 gboolean
12577 clutter_actor_get_reactive (ClutterActor *actor)
12578 {
12579   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12580
12581   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12582 }
12583
12584 /**
12585  * clutter_actor_get_anchor_point:
12586  * @self: a #ClutterActor
12587  * @anchor_x: (out): return location for the X coordinate of the anchor point
12588  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12589  *
12590  * Gets the current anchor point of the @actor in pixels.
12591  *
12592  * Since: 0.6
12593  */
12594 void
12595 clutter_actor_get_anchor_point (ClutterActor *self,
12596                                 gfloat       *anchor_x,
12597                                 gfloat       *anchor_y)
12598 {
12599   const ClutterTransformInfo *info;
12600
12601   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12602
12603   info = _clutter_actor_get_transform_info_or_defaults (self);
12604   clutter_anchor_coord_get_units (self, &info->anchor,
12605                                   anchor_x,
12606                                   anchor_y,
12607                                   NULL);
12608 }
12609
12610 /**
12611  * clutter_actor_set_anchor_point:
12612  * @self: a #ClutterActor
12613  * @anchor_x: X coordinate of the anchor point
12614  * @anchor_y: Y coordinate of the anchor point
12615  *
12616  * Sets an anchor point for @self. The anchor point is a point in the
12617  * coordinate space of an actor to which the actor position within its
12618  * parent is relative; the default is (0, 0), i.e. the top-left corner
12619  * of the actor.
12620  *
12621  * Since: 0.6
12622  */
12623 void
12624 clutter_actor_set_anchor_point (ClutterActor *self,
12625                                 gfloat        anchor_x,
12626                                 gfloat        anchor_y)
12627 {
12628   ClutterTransformInfo *info;
12629   ClutterActorPrivate *priv;
12630   gboolean changed = FALSE;
12631   gfloat old_anchor_x, old_anchor_y;
12632   GObject *obj;
12633
12634   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12635
12636   obj = G_OBJECT (self);
12637   priv = self->priv;
12638   info = _clutter_actor_get_transform_info (self);
12639
12640   g_object_freeze_notify (obj);
12641
12642   clutter_anchor_coord_get_units (self, &info->anchor,
12643                                   &old_anchor_x,
12644                                   &old_anchor_y,
12645                                   NULL);
12646
12647   if (info->anchor.is_fractional)
12648     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12649
12650   if (old_anchor_x != anchor_x)
12651     {
12652       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12653       changed = TRUE;
12654     }
12655
12656   if (old_anchor_y != anchor_y)
12657     {
12658       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12659       changed = TRUE;
12660     }
12661
12662   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12663
12664   if (changed)
12665     {
12666       priv->transform_valid = FALSE;
12667       clutter_actor_queue_redraw (self);
12668     }
12669
12670   g_object_thaw_notify (obj);
12671 }
12672
12673 /**
12674  * clutter_actor_get_anchor_point_gravity:
12675  * @self: a #ClutterActor
12676  *
12677  * Retrieves the anchor position expressed as a #ClutterGravity. If
12678  * the anchor point was specified using pixels or units this will
12679  * return %CLUTTER_GRAVITY_NONE.
12680  *
12681  * Return value: the #ClutterGravity used by the anchor point
12682  *
12683  * Since: 1.0
12684  */
12685 ClutterGravity
12686 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12687 {
12688   const ClutterTransformInfo *info;
12689
12690   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12691
12692   info = _clutter_actor_get_transform_info_or_defaults (self);
12693
12694   return clutter_anchor_coord_get_gravity (&info->anchor);
12695 }
12696
12697 /**
12698  * clutter_actor_move_anchor_point:
12699  * @self: a #ClutterActor
12700  * @anchor_x: X coordinate of the anchor point
12701  * @anchor_y: Y coordinate of the anchor point
12702  *
12703  * Sets an anchor point for the actor, and adjusts the actor postion so that
12704  * the relative position of the actor toward its parent remains the same.
12705  *
12706  * Since: 0.6
12707  */
12708 void
12709 clutter_actor_move_anchor_point (ClutterActor *self,
12710                                  gfloat        anchor_x,
12711                                  gfloat        anchor_y)
12712 {
12713   gfloat old_anchor_x, old_anchor_y;
12714   const ClutterTransformInfo *info;
12715
12716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12717
12718   info = _clutter_actor_get_transform_info (self);
12719   clutter_anchor_coord_get_units (self, &info->anchor,
12720                                   &old_anchor_x,
12721                                   &old_anchor_y,
12722                                   NULL);
12723
12724   g_object_freeze_notify (G_OBJECT (self));
12725
12726   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12727
12728   if (self->priv->position_set)
12729     clutter_actor_move_by (self,
12730                            anchor_x - old_anchor_x,
12731                            anchor_y - old_anchor_y);
12732
12733   g_object_thaw_notify (G_OBJECT (self));
12734 }
12735
12736 /**
12737  * clutter_actor_move_anchor_point_from_gravity:
12738  * @self: a #ClutterActor
12739  * @gravity: #ClutterGravity.
12740  *
12741  * Sets an anchor point on the actor based on the given gravity, adjusting the
12742  * actor postion so that its relative position within its parent remains
12743  * unchanged.
12744  *
12745  * Since version 1.0 the anchor point will be stored as a gravity so
12746  * that if the actor changes size then the anchor point will move. For
12747  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12748  * and later double the size of the actor, the anchor point will move
12749  * to the bottom right.
12750  *
12751  * Since: 0.6
12752  */
12753 void
12754 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12755                                               ClutterGravity  gravity)
12756 {
12757   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12758   const ClutterTransformInfo *info;
12759   ClutterActorPrivate *priv;
12760
12761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12762
12763   priv = self->priv;
12764   info = _clutter_actor_get_transform_info (self);
12765
12766   g_object_freeze_notify (G_OBJECT (self));
12767
12768   clutter_anchor_coord_get_units (self, &info->anchor,
12769                                   &old_anchor_x,
12770                                   &old_anchor_y,
12771                                   NULL);
12772   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12773   clutter_anchor_coord_get_units (self, &info->anchor,
12774                                   &new_anchor_x,
12775                                   &new_anchor_y,
12776                                   NULL);
12777
12778   if (priv->position_set)
12779     clutter_actor_move_by (self,
12780                            new_anchor_x - old_anchor_x,
12781                            new_anchor_y - old_anchor_y);
12782
12783   g_object_thaw_notify (G_OBJECT (self));
12784 }
12785
12786 /**
12787  * clutter_actor_set_anchor_point_from_gravity:
12788  * @self: a #ClutterActor
12789  * @gravity: #ClutterGravity.
12790  *
12791  * Sets an anchor point on the actor, based on the given gravity (this is a
12792  * convenience function wrapping clutter_actor_set_anchor_point()).
12793  *
12794  * Since version 1.0 the anchor point will be stored as a gravity so
12795  * that if the actor changes size then the anchor point will move. For
12796  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12797  * and later double the size of the actor, the anchor point will move
12798  * to the bottom right.
12799  *
12800  * Since: 0.6
12801  */
12802 void
12803 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12804                                              ClutterGravity  gravity)
12805 {
12806   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12807
12808   if (gravity == CLUTTER_GRAVITY_NONE)
12809     clutter_actor_set_anchor_point (self, 0, 0);
12810   else
12811     {
12812       GObject *obj = G_OBJECT (self);
12813       ClutterTransformInfo *info;
12814
12815       g_object_freeze_notify (obj);
12816
12817       info = _clutter_actor_get_transform_info (self);
12818       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12819
12820       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12821       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12822       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12823
12824       self->priv->transform_valid = FALSE;
12825
12826       clutter_actor_queue_redraw (self);
12827
12828       g_object_thaw_notify (obj);
12829     }
12830 }
12831
12832 static void
12833 clutter_actor_store_content_box (ClutterActor *self,
12834                                  const ClutterActorBox *box)
12835 {
12836   if (box != NULL)
12837     {
12838       self->priv->content_box = *box;
12839       self->priv->content_box_valid = TRUE;
12840     }
12841   else
12842     self->priv->content_box_valid = FALSE;
12843
12844   clutter_actor_queue_redraw (self);
12845
12846   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12847 }
12848
12849 static void
12850 clutter_container_iface_init (ClutterContainerIface *iface)
12851 {
12852   /* we don't override anything, as ClutterContainer already has a default
12853    * implementation that we can use, and which calls into our own API.
12854    */
12855 }
12856
12857 typedef enum
12858 {
12859   PARSE_X,
12860   PARSE_Y,
12861   PARSE_WIDTH,
12862   PARSE_HEIGHT,
12863   PARSE_ANCHOR_X,
12864   PARSE_ANCHOR_Y
12865 } ParseDimension;
12866
12867 static gfloat
12868 parse_units (ClutterActor   *self,
12869              ParseDimension  dimension,
12870              JsonNode       *node)
12871 {
12872   GValue value = G_VALUE_INIT;
12873   gfloat retval = 0;
12874
12875   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12876     return 0;
12877
12878   json_node_get_value (node, &value);
12879
12880   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12881     {
12882       retval = (gfloat) g_value_get_int64 (&value);
12883     }
12884   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12885     {
12886       retval = g_value_get_double (&value);
12887     }
12888   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12889     {
12890       ClutterUnits units;
12891       gboolean res;
12892
12893       res = clutter_units_from_string (&units, g_value_get_string (&value));
12894       if (res)
12895         retval = clutter_units_to_pixels (&units);
12896       else
12897         {
12898           g_warning ("Invalid value '%s': integers, strings or floating point "
12899                      "values can be used for the x, y, width and height "
12900                      "properties. Valid modifiers for strings are 'px', 'mm', "
12901                      "'pt' and 'em'.",
12902                      g_value_get_string (&value));
12903           retval = 0;
12904         }
12905     }
12906   else
12907     {
12908       g_warning ("Invalid value of type '%s': integers, strings of floating "
12909                  "point values can be used for the x, y, width, height "
12910                  "anchor-x and anchor-y properties.",
12911                  g_type_name (G_VALUE_TYPE (&value)));
12912     }
12913
12914   g_value_unset (&value);
12915
12916   return retval;
12917 }
12918
12919 typedef struct {
12920   ClutterRotateAxis axis;
12921
12922   gdouble angle;
12923
12924   gfloat center_x;
12925   gfloat center_y;
12926   gfloat center_z;
12927 } RotationInfo;
12928
12929 static inline gboolean
12930 parse_rotation_array (ClutterActor *actor,
12931                       JsonArray    *array,
12932                       RotationInfo *info)
12933 {
12934   JsonNode *element;
12935
12936   if (json_array_get_length (array) != 2)
12937     return FALSE;
12938
12939   /* angle */
12940   element = json_array_get_element (array, 0);
12941   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12942     info->angle = json_node_get_double (element);
12943   else
12944     return FALSE;
12945
12946   /* center */
12947   element = json_array_get_element (array, 1);
12948   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12949     {
12950       JsonArray *center = json_node_get_array (element);
12951
12952       if (json_array_get_length (center) != 2)
12953         return FALSE;
12954
12955       switch (info->axis)
12956         {
12957         case CLUTTER_X_AXIS:
12958           info->center_y = parse_units (actor, PARSE_Y,
12959                                         json_array_get_element (center, 0));
12960           info->center_z = parse_units (actor, PARSE_Y,
12961                                         json_array_get_element (center, 1));
12962           return TRUE;
12963
12964         case CLUTTER_Y_AXIS:
12965           info->center_x = parse_units (actor, PARSE_X,
12966                                         json_array_get_element (center, 0));
12967           info->center_z = parse_units (actor, PARSE_X,
12968                                         json_array_get_element (center, 1));
12969           return TRUE;
12970
12971         case CLUTTER_Z_AXIS:
12972           info->center_x = parse_units (actor, PARSE_X,
12973                                         json_array_get_element (center, 0));
12974           info->center_y = parse_units (actor, PARSE_Y,
12975                                         json_array_get_element (center, 1));
12976           return TRUE;
12977         }
12978     }
12979
12980   return FALSE;
12981 }
12982
12983 static gboolean
12984 parse_rotation (ClutterActor *actor,
12985                 JsonNode     *node,
12986                 RotationInfo *info)
12987 {
12988   JsonArray *array;
12989   guint len, i;
12990   gboolean retval = FALSE;
12991
12992   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12993     {
12994       g_warning ("Invalid node of type '%s' found, expecting an array",
12995                  json_node_type_name (node));
12996       return FALSE;
12997     }
12998
12999   array = json_node_get_array (node);
13000   len = json_array_get_length (array);
13001
13002   for (i = 0; i < len; i++)
13003     {
13004       JsonNode *element = json_array_get_element (array, i);
13005       JsonObject *object;
13006       JsonNode *member;
13007
13008       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
13009         {
13010           g_warning ("Invalid node of type '%s' found, expecting an object",
13011                      json_node_type_name (element));
13012           return FALSE;
13013         }
13014
13015       object = json_node_get_object (element);
13016
13017       if (json_object_has_member (object, "x-axis"))
13018         {
13019           member = json_object_get_member (object, "x-axis");
13020
13021           info->axis = CLUTTER_X_AXIS;
13022
13023           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13024             {
13025               info->angle = json_node_get_double (member);
13026               retval = TRUE;
13027             }
13028           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13029             retval = parse_rotation_array (actor,
13030                                            json_node_get_array (member),
13031                                            info);
13032           else
13033             retval = FALSE;
13034         }
13035       else if (json_object_has_member (object, "y-axis"))
13036         {
13037           member = json_object_get_member (object, "y-axis");
13038
13039           info->axis = CLUTTER_Y_AXIS;
13040
13041           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13042             {
13043               info->angle = json_node_get_double (member);
13044               retval = TRUE;
13045             }
13046           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13047             retval = parse_rotation_array (actor,
13048                                            json_node_get_array (member),
13049                                            info);
13050           else
13051             retval = FALSE;
13052         }
13053       else if (json_object_has_member (object, "z-axis"))
13054         {
13055           member = json_object_get_member (object, "z-axis");
13056
13057           info->axis = CLUTTER_Z_AXIS;
13058
13059           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13060             {
13061               info->angle = json_node_get_double (member);
13062               retval = TRUE;
13063             }
13064           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13065             retval = parse_rotation_array (actor,
13066                                            json_node_get_array (member),
13067                                            info);
13068           else
13069             retval = FALSE;
13070         }
13071     }
13072
13073   return retval;
13074 }
13075
13076 static GSList *
13077 parse_actor_metas (ClutterScript *script,
13078                    ClutterActor  *actor,
13079                    JsonNode      *node)
13080 {
13081   GList *elements, *l;
13082   GSList *retval = NULL;
13083
13084   if (!JSON_NODE_HOLDS_ARRAY (node))
13085     return NULL;
13086
13087   elements = json_array_get_elements (json_node_get_array (node));
13088
13089   for (l = elements; l != NULL; l = l->next)
13090     {
13091       JsonNode *element = l->data;
13092       const gchar *id_ = _clutter_script_get_id_from_node (element);
13093       GObject *meta;
13094
13095       if (id_ == NULL || *id_ == '\0')
13096         continue;
13097
13098       meta = clutter_script_get_object (script, id_);
13099       if (meta == NULL)
13100         continue;
13101
13102       retval = g_slist_prepend (retval, meta);
13103     }
13104
13105   g_list_free (elements);
13106
13107   return g_slist_reverse (retval);
13108 }
13109
13110 static GSList *
13111 parse_behaviours (ClutterScript *script,
13112                   ClutterActor  *actor,
13113                   JsonNode      *node)
13114 {
13115   GList *elements, *l;
13116   GSList *retval = NULL;
13117
13118   if (!JSON_NODE_HOLDS_ARRAY (node))
13119     return NULL;
13120
13121   elements = json_array_get_elements (json_node_get_array (node));
13122
13123   for (l = elements; l != NULL; l = l->next)
13124     {
13125       JsonNode *element = l->data;
13126       const gchar *id_ = _clutter_script_get_id_from_node (element);
13127       GObject *behaviour;
13128
13129       if (id_ == NULL || *id_ == '\0')
13130         continue;
13131
13132       behaviour = clutter_script_get_object (script, id_);
13133       if (behaviour == NULL)
13134         continue;
13135
13136       retval = g_slist_prepend (retval, behaviour);
13137     }
13138
13139   g_list_free (elements);
13140
13141   return g_slist_reverse (retval);
13142 }
13143
13144 static ClutterMargin *
13145 parse_margin (ClutterActor *self,
13146               JsonNode     *node)
13147 {
13148   ClutterMargin *margin;
13149   JsonArray *array;
13150
13151   if (!JSON_NODE_HOLDS_ARRAY (node))
13152     {
13153       g_warning ("The margin property must be an array of 1 to 4 elements");
13154       return NULL;
13155     }
13156
13157   margin = clutter_margin_new ();
13158   array = json_node_get_array (node);
13159   switch (json_array_get_length (array))
13160     {
13161     case 1:
13162       margin->top = margin->right = margin->bottom = margin->left =
13163         parse_units (self, 0, json_array_get_element (array, 0));
13164       break;
13165
13166     case 2:
13167       margin->top = margin->bottom =
13168         parse_units (self, 0, json_array_get_element (array, 0));
13169       margin->right = margin->left =
13170         parse_units (self, 0, json_array_get_element (array, 1));
13171       break;
13172
13173     case 3:
13174       margin->top =
13175         parse_units (self, 0, json_array_get_element (array, 0));
13176       margin->right = margin->left =
13177         parse_units (self, 0, json_array_get_element (array, 1));
13178       margin->bottom =
13179         parse_units (self, 0, json_array_get_element (array, 2));
13180       break;
13181
13182     case 4:
13183       margin->top =
13184         parse_units (self, 0, json_array_get_element (array, 0));
13185       margin->right =
13186         parse_units (self, 0, json_array_get_element (array, 1));
13187       margin->bottom =
13188         parse_units (self, 0, json_array_get_element (array, 2));
13189       margin->left =
13190         parse_units (self, 0, json_array_get_element (array, 3));
13191       break;
13192
13193     default:
13194       g_warning ("The margin property must be an array of 1 to 4 elements");
13195       clutter_margin_free (margin);
13196       return NULL;
13197     }
13198   return margin;
13199 }
13200
13201 static gboolean
13202 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13203                                  ClutterScript     *script,
13204                                  GValue            *value,
13205                                  const gchar       *name,
13206                                  JsonNode          *node)
13207 {
13208   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13209   gboolean retval = FALSE;
13210
13211   if ((name[0] == 'x' && name[1] == '\0') ||
13212       (name[0] == 'y' && name[1] == '\0') ||
13213       (strcmp (name, "width") == 0) ||
13214       (strcmp (name, "height") == 0) ||
13215       (strcmp (name, "anchor_x") == 0) ||
13216       (strcmp (name, "anchor_y") == 0))
13217     {
13218       ParseDimension dimension;
13219       gfloat units;
13220
13221       if (name[0] == 'x')
13222         dimension = PARSE_X;
13223       else if (name[0] == 'y')
13224         dimension = PARSE_Y;
13225       else if (name[0] == 'w')
13226         dimension = PARSE_WIDTH;
13227       else if (name[0] == 'h')
13228         dimension = PARSE_HEIGHT;
13229       else if (name[0] == 'a' && name[7] == 'x')
13230         dimension = PARSE_ANCHOR_X;
13231       else if (name[0] == 'a' && name[7] == 'y')
13232         dimension = PARSE_ANCHOR_Y;
13233       else
13234         return FALSE;
13235
13236       units = parse_units (actor, dimension, node);
13237
13238       /* convert back to pixels: all properties are pixel-based */
13239       g_value_init (value, G_TYPE_FLOAT);
13240       g_value_set_float (value, units);
13241
13242       retval = TRUE;
13243     }
13244   else if (strcmp (name, "rotation") == 0)
13245     {
13246       RotationInfo *info;
13247
13248       info = g_slice_new0 (RotationInfo);
13249       retval = parse_rotation (actor, node, info);
13250
13251       if (retval)
13252         {
13253           g_value_init (value, G_TYPE_POINTER);
13254           g_value_set_pointer (value, info);
13255         }
13256       else
13257         g_slice_free (RotationInfo, info);
13258     }
13259   else if (strcmp (name, "behaviours") == 0)
13260     {
13261       GSList *l;
13262
13263 #ifdef CLUTTER_ENABLE_DEBUG
13264       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13265         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13266                                      "and it should not be used in newly "
13267                                      "written ClutterScript definitions.");
13268 #endif
13269
13270       l = parse_behaviours (script, actor, node);
13271
13272       g_value_init (value, G_TYPE_POINTER);
13273       g_value_set_pointer (value, l);
13274
13275       retval = TRUE;
13276     }
13277   else if (strcmp (name, "actions") == 0 ||
13278            strcmp (name, "constraints") == 0 ||
13279            strcmp (name, "effects") == 0)
13280     {
13281       GSList *l;
13282
13283       l = parse_actor_metas (script, actor, node);
13284
13285       g_value_init (value, G_TYPE_POINTER);
13286       g_value_set_pointer (value, l);
13287
13288       retval = TRUE;
13289     }
13290   else if (strcmp (name, "margin") == 0)
13291     {
13292       ClutterMargin *margin = parse_margin (actor, node);
13293
13294       if (margin)
13295         {
13296           g_value_init (value, CLUTTER_TYPE_MARGIN);
13297           g_value_set_boxed (value, margin);
13298           retval = TRUE;
13299         }
13300     }
13301
13302   return retval;
13303 }
13304
13305 static void
13306 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13307                                    ClutterScript     *script,
13308                                    const gchar       *name,
13309                                    const GValue      *value)
13310 {
13311   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13312
13313 #ifdef CLUTTER_ENABLE_DEBUG
13314   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13315     {
13316       gchar *tmp = g_strdup_value_contents (value);
13317
13318       CLUTTER_NOTE (SCRIPT,
13319                     "in ClutterActor::set_custom_property('%s') = %s",
13320                     name,
13321                     tmp);
13322
13323       g_free (tmp);
13324     }
13325 #endif /* CLUTTER_ENABLE_DEBUG */
13326
13327   if (strcmp (name, "rotation") == 0)
13328     {
13329       RotationInfo *info;
13330
13331       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13332         return;
13333
13334       info = g_value_get_pointer (value);
13335
13336       clutter_actor_set_rotation (actor,
13337                                   info->axis, info->angle,
13338                                   info->center_x,
13339                                   info->center_y,
13340                                   info->center_z);
13341
13342       g_slice_free (RotationInfo, info);
13343
13344       return;
13345     }
13346
13347   if (strcmp (name, "behaviours") == 0)
13348     {
13349       GSList *behaviours, *l;
13350
13351       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13352         return;
13353
13354       behaviours = g_value_get_pointer (value);
13355       for (l = behaviours; l != NULL; l = l->next)
13356         {
13357           ClutterBehaviour *behaviour = l->data;
13358
13359           clutter_behaviour_apply (behaviour, actor);
13360         }
13361
13362       g_slist_free (behaviours);
13363
13364       return;
13365     }
13366
13367   if (strcmp (name, "actions") == 0 ||
13368       strcmp (name, "constraints") == 0 ||
13369       strcmp (name, "effects") == 0)
13370     {
13371       GSList *metas, *l;
13372
13373       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13374         return;
13375
13376       metas = g_value_get_pointer (value);
13377       for (l = metas; l != NULL; l = l->next)
13378         {
13379           if (name[0] == 'a')
13380             clutter_actor_add_action (actor, l->data);
13381
13382           if (name[0] == 'c')
13383             clutter_actor_add_constraint (actor, l->data);
13384
13385           if (name[0] == 'e')
13386             clutter_actor_add_effect (actor, l->data);
13387         }
13388
13389       g_slist_free (metas);
13390
13391       return;
13392     }
13393   if (strcmp (name, "margin") == 0)
13394     {
13395       clutter_actor_set_margin (actor, g_value_get_boxed (value));
13396       return;
13397     }
13398
13399   g_object_set_property (G_OBJECT (scriptable), name, value);
13400 }
13401
13402 static void
13403 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13404 {
13405   iface->parse_custom_node = clutter_actor_parse_custom_node;
13406   iface->set_custom_property = clutter_actor_set_custom_property;
13407 }
13408
13409 static ClutterActorMeta *
13410 get_meta_from_animation_property (ClutterActor  *actor,
13411                                   const gchar   *name,
13412                                   gchar        **name_p)
13413 {
13414   ClutterActorPrivate *priv = actor->priv;
13415   ClutterActorMeta *meta = NULL;
13416   gchar **tokens;
13417
13418   /* if this is not a special property, fall through */
13419   if (name[0] != '@')
13420     return NULL;
13421
13422   /* detect the properties named using the following spec:
13423    *
13424    *   @<section>.<meta-name>.<property-name>
13425    *
13426    * where <section> can be one of the following:
13427    *
13428    *   - actions
13429    *   - constraints
13430    *   - effects
13431    *
13432    * and <meta-name> is the name set on a specific ActorMeta
13433    */
13434
13435   tokens = g_strsplit (name + 1, ".", -1);
13436   if (tokens == NULL || g_strv_length (tokens) != 3)
13437     {
13438       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13439                     name + 1);
13440       g_strfreev (tokens);
13441       return NULL;
13442     }
13443
13444   if (strcmp (tokens[0], "actions") == 0)
13445     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13446
13447   if (strcmp (tokens[0], "constraints") == 0)
13448     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13449
13450   if (strcmp (tokens[0], "effects") == 0)
13451     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13452
13453   if (name_p != NULL)
13454     *name_p = g_strdup (tokens[2]);
13455
13456   CLUTTER_NOTE (ANIMATION,
13457                 "Looking for property '%s' of object '%s' in section '%s'",
13458                 tokens[2],
13459                 tokens[1],
13460                 tokens[0]);
13461
13462   g_strfreev (tokens);
13463
13464   return meta;
13465 }
13466
13467 static GParamSpec *
13468 clutter_actor_find_property (ClutterAnimatable *animatable,
13469                              const gchar       *property_name)
13470 {
13471   ClutterActorMeta *meta = NULL;
13472   GObjectClass *klass = NULL;
13473   GParamSpec *pspec = NULL;
13474   gchar *p_name = NULL;
13475
13476   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13477                                            property_name,
13478                                            &p_name);
13479
13480   if (meta != NULL)
13481     {
13482       klass = G_OBJECT_GET_CLASS (meta);
13483
13484       pspec = g_object_class_find_property (klass, p_name);
13485     }
13486   else
13487     {
13488       klass = G_OBJECT_GET_CLASS (animatable);
13489
13490       pspec = g_object_class_find_property (klass, property_name);
13491     }
13492
13493   g_free (p_name);
13494
13495   return pspec;
13496 }
13497
13498 static void
13499 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13500                                  const gchar       *property_name,
13501                                  GValue            *initial)
13502 {
13503   ClutterActorMeta *meta = NULL;
13504   gchar *p_name = NULL;
13505
13506   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13507                                            property_name,
13508                                            &p_name);
13509
13510   if (meta != NULL)
13511     g_object_get_property (G_OBJECT (meta), p_name, initial);
13512   else
13513     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13514
13515   g_free (p_name);
13516 }
13517
13518 /*
13519  * clutter_actor_set_animatable_property:
13520  * @actor: a #ClutterActor
13521  * @prop_id: the paramspec id
13522  * @value: the value to set
13523  * @pspec: the paramspec
13524  *
13525  * Sets values of animatable properties.
13526  *
13527  * This is a variant of clutter_actor_set_property() that gets called
13528  * by the #ClutterAnimatable implementation of #ClutterActor for the
13529  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13530  * #GParamSpec.
13531  *
13532  * Unlike the implementation of #GObjectClass.set_property(), this
13533  * function will not update the interval if a transition involving an
13534  * animatable property is in progress - this avoids cycles with the
13535  * transition API calling the public API.
13536  */
13537 static void
13538 clutter_actor_set_animatable_property (ClutterActor *actor,
13539                                        guint         prop_id,
13540                                        const GValue *value,
13541                                        GParamSpec   *pspec)
13542 {
13543   GObject *obj = G_OBJECT (actor);
13544
13545   g_object_freeze_notify (obj);
13546
13547   switch (prop_id)
13548     {
13549     case PROP_X:
13550       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13551       break;
13552
13553     case PROP_Y:
13554       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13555       break;
13556
13557     case PROP_POSITION:
13558       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13559       break;
13560
13561     case PROP_WIDTH:
13562       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13563       break;
13564
13565     case PROP_HEIGHT:
13566       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13567       break;
13568
13569     case PROP_SIZE:
13570       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13571       break;
13572
13573     case PROP_ALLOCATION:
13574       clutter_actor_allocate_internal (actor,
13575                                        g_value_get_boxed (value),
13576                                        actor->priv->allocation_flags);
13577       break;
13578
13579     case PROP_DEPTH:
13580       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13581       break;
13582
13583     case PROP_OPACITY:
13584       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13585       break;
13586
13587     case PROP_BACKGROUND_COLOR:
13588       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13589       break;
13590
13591     case PROP_SCALE_X:
13592       clutter_actor_set_scale_factor_internal (actor,
13593                                                g_value_get_double (value),
13594                                                pspec);
13595       break;
13596
13597     case PROP_SCALE_Y:
13598       clutter_actor_set_scale_factor_internal (actor,
13599                                                g_value_get_double (value),
13600                                                pspec);
13601       break;
13602
13603     case PROP_ROTATION_ANGLE_X:
13604       clutter_actor_set_rotation_angle_internal (actor,
13605                                                  CLUTTER_X_AXIS,
13606                                                  g_value_get_double (value));
13607       break;
13608
13609     case PROP_ROTATION_ANGLE_Y:
13610       clutter_actor_set_rotation_angle_internal (actor,
13611                                                  CLUTTER_Y_AXIS,
13612                                                  g_value_get_double (value));
13613       break;
13614
13615     case PROP_ROTATION_ANGLE_Z:
13616       clutter_actor_set_rotation_angle_internal (actor,
13617                                                  CLUTTER_Z_AXIS,
13618                                                  g_value_get_double (value));
13619       break;
13620
13621     case PROP_CONTENT_BOX:
13622       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13623       break;
13624
13625     default:
13626       g_object_set_property (obj, pspec->name, value);
13627       break;
13628     }
13629
13630   g_object_thaw_notify (obj);
13631 }
13632
13633 static void
13634 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13635                                const gchar       *property_name,
13636                                const GValue      *final)
13637 {
13638   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13639   ClutterActorMeta *meta = NULL;
13640   gchar *p_name = NULL;
13641
13642   meta = get_meta_from_animation_property (actor,
13643                                            property_name,
13644                                            &p_name);
13645   if (meta != NULL)
13646     g_object_set_property (G_OBJECT (meta), p_name, final);
13647   else
13648     {
13649       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13650       GParamSpec *pspec;
13651
13652       pspec = g_object_class_find_property (obj_class, property_name);
13653
13654       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13655         {
13656           /* XXX - I'm going to the special hell for this */
13657           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13658         }
13659       else
13660         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13661     }
13662
13663   g_free (p_name);
13664 }
13665
13666 static void
13667 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13668 {
13669   iface->find_property = clutter_actor_find_property;
13670   iface->get_initial_state = clutter_actor_get_initial_state;
13671   iface->set_final_state = clutter_actor_set_final_state;
13672 }
13673
13674 /**
13675  * clutter_actor_transform_stage_point:
13676  * @self: A #ClutterActor
13677  * @x: (in): x screen coordinate of the point to unproject
13678  * @y: (in): y screen coordinate of the point to unproject
13679  * @x_out: (out): return location for the unprojected x coordinance
13680  * @y_out: (out): return location for the unprojected y coordinance
13681  *
13682  * This function translates screen coordinates (@x, @y) to
13683  * coordinates relative to the actor. For example, it can be used to translate
13684  * screen events from global screen coordinates into actor-local coordinates.
13685  *
13686  * The conversion can fail, notably if the transform stack results in the
13687  * actor being projected on the screen as a mere line.
13688  *
13689  * The conversion should not be expected to be pixel-perfect due to the
13690  * nature of the operation. In general the error grows when the skewing
13691  * of the actor rectangle on screen increases.
13692  *
13693  * <note><para>This function can be computationally intensive.</para></note>
13694  *
13695  * <note><para>This function only works when the allocation is up-to-date,
13696  * i.e. inside of paint().</para></note>
13697  *
13698  * Return value: %TRUE if conversion was successful.
13699  *
13700  * Since: 0.6
13701  */
13702 gboolean
13703 clutter_actor_transform_stage_point (ClutterActor *self,
13704                                      gfloat        x,
13705                                      gfloat        y,
13706                                      gfloat       *x_out,
13707                                      gfloat       *y_out)
13708 {
13709   ClutterVertex v[4];
13710   float ST[3][3];
13711   float RQ[3][3];
13712   int du, dv, xi, yi;
13713   float px, py;
13714   float xf, yf, wf, det;
13715   ClutterActorPrivate *priv;
13716
13717   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13718
13719   priv = self->priv;
13720
13721   /* This implementation is based on the quad -> quad projection algorithm
13722    * described by Paul Heckbert in:
13723    *
13724    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13725    *
13726    * and the sample implementation at:
13727    *
13728    *   http://www.cs.cmu.edu/~ph/src/texfund/
13729    *
13730    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13731    * quad to rectangle only, which significantly simplifies things; the
13732    * function calls have been unrolled, and most of the math is done in fixed
13733    * point.
13734    */
13735
13736   clutter_actor_get_abs_allocation_vertices (self, v);
13737
13738   /* Keeping these as ints simplifies the multiplication (no significant
13739    * loss of precision here).
13740    */
13741   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13742   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13743
13744   if (!du || !dv)
13745     return FALSE;
13746
13747 #define UX2FP(x)        (x)
13748 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13749
13750   /* First, find mapping from unit uv square to xy quadrilateral; this
13751    * equivalent to the pmap_square_quad() functions in the sample
13752    * implementation, which we can simplify, since our target is always
13753    * a rectangle.
13754    */
13755   px = v[0].x - v[1].x + v[3].x - v[2].x;
13756   py = v[0].y - v[1].y + v[3].y - v[2].y;
13757
13758   if (!px && !py)
13759     {
13760       /* affine transform */
13761       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13762       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13763       RQ[2][0] = UX2FP (v[0].x);
13764       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13765       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13766       RQ[2][1] = UX2FP (v[0].y);
13767       RQ[0][2] = 0;
13768       RQ[1][2] = 0;
13769       RQ[2][2] = 1.0;
13770     }
13771   else
13772     {
13773       /* projective transform */
13774       double dx1, dx2, dy1, dy2, del;
13775
13776       dx1 = UX2FP (v[1].x - v[3].x);
13777       dx2 = UX2FP (v[2].x - v[3].x);
13778       dy1 = UX2FP (v[1].y - v[3].y);
13779       dy2 = UX2FP (v[2].y - v[3].y);
13780
13781       del = DET2FP (dx1, dx2, dy1, dy2);
13782       if (!del)
13783         return FALSE;
13784
13785       /*
13786        * The division here needs to be done in floating point for
13787        * precisions reasons.
13788        */
13789       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13790       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13791       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13792       RQ[2][2] = 1.0;
13793       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13794       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13795       RQ[2][0] = UX2FP (v[0].x);
13796       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13797       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13798       RQ[2][1] = UX2FP (v[0].y);
13799     }
13800
13801   /*
13802    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13803    * square. Since our rectangle is based at 0,0 we only need to scale.
13804    */
13805   RQ[0][0] /= du;
13806   RQ[1][0] /= dv;
13807   RQ[0][1] /= du;
13808   RQ[1][1] /= dv;
13809   RQ[0][2] /= du;
13810   RQ[1][2] /= dv;
13811
13812   /*
13813    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13814    * inverse of that.
13815    */
13816   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13817   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13818   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13819   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13820   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13821   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13822   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13823   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13824   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13825
13826   /*
13827    * Check the resulting matrix is OK.
13828    */
13829   det = (RQ[0][0] * ST[0][0])
13830       + (RQ[0][1] * ST[0][1])
13831       + (RQ[0][2] * ST[0][2]);
13832   if (!det)
13833     return FALSE;
13834
13835   /*
13836    * Now transform our point with the ST matrix; the notional w
13837    * coordinate is 1, hence the last part is simply added.
13838    */
13839   xi = (int) x;
13840   yi = (int) y;
13841
13842   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13843   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13844   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13845
13846   if (x_out)
13847     *x_out = xf / wf;
13848
13849   if (y_out)
13850     *y_out = yf / wf;
13851
13852 #undef UX2FP
13853 #undef DET2FP
13854
13855   return TRUE;
13856 }
13857
13858 /**
13859  * clutter_actor_is_rotated:
13860  * @self: a #ClutterActor
13861  *
13862  * Checks whether any rotation is applied to the actor.
13863  *
13864  * Return value: %TRUE if the actor is rotated.
13865  *
13866  * Since: 0.6
13867  */
13868 gboolean
13869 clutter_actor_is_rotated (ClutterActor *self)
13870 {
13871   const ClutterTransformInfo *info;
13872
13873   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13874
13875   info = _clutter_actor_get_transform_info_or_defaults (self);
13876
13877   if (info->rx_angle || info->ry_angle || info->rz_angle)
13878     return TRUE;
13879
13880   return FALSE;
13881 }
13882
13883 /**
13884  * clutter_actor_is_scaled:
13885  * @self: a #ClutterActor
13886  *
13887  * Checks whether the actor is scaled in either dimension.
13888  *
13889  * Return value: %TRUE if the actor is scaled.
13890  *
13891  * Since: 0.6
13892  */
13893 gboolean
13894 clutter_actor_is_scaled (ClutterActor *self)
13895 {
13896   const ClutterTransformInfo *info;
13897
13898   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13899
13900   info = _clutter_actor_get_transform_info_or_defaults (self);
13901
13902   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13903     return TRUE;
13904
13905   return FALSE;
13906 }
13907
13908 ClutterActor *
13909 _clutter_actor_get_stage_internal (ClutterActor *actor)
13910 {
13911   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13912     actor = actor->priv->parent;
13913
13914   return actor;
13915 }
13916
13917 /**
13918  * clutter_actor_get_stage:
13919  * @actor: a #ClutterActor
13920  *
13921  * Retrieves the #ClutterStage where @actor is contained.
13922  *
13923  * Return value: (transfer none) (type Clutter.Stage): the stage
13924  *   containing the actor, or %NULL
13925  *
13926  * Since: 0.8
13927  */
13928 ClutterActor *
13929 clutter_actor_get_stage (ClutterActor *actor)
13930 {
13931   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13932
13933   return _clutter_actor_get_stage_internal (actor);
13934 }
13935
13936 /**
13937  * clutter_actor_allocate_available_size:
13938  * @self: a #ClutterActor
13939  * @x: the actor's X coordinate
13940  * @y: the actor's Y coordinate
13941  * @available_width: the maximum available width, or -1 to use the
13942  *   actor's natural width
13943  * @available_height: the maximum available height, or -1 to use the
13944  *   actor's natural height
13945  * @flags: flags controlling the allocation
13946  *
13947  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13948  * preferred size, but limiting it to the maximum available width
13949  * and height provided.
13950  *
13951  * This function will do the right thing when dealing with the
13952  * actor's request mode.
13953  *
13954  * The implementation of this function is equivalent to:
13955  *
13956  * |[
13957  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13958  *     {
13959  *       clutter_actor_get_preferred_width (self, available_height,
13960  *                                          &amp;min_width,
13961  *                                          &amp;natural_width);
13962  *       width = CLAMP (natural_width, min_width, available_width);
13963  *
13964  *       clutter_actor_get_preferred_height (self, width,
13965  *                                           &amp;min_height,
13966  *                                           &amp;natural_height);
13967  *       height = CLAMP (natural_height, min_height, available_height);
13968  *     }
13969  *   else
13970  *     {
13971  *       clutter_actor_get_preferred_height (self, available_width,
13972  *                                           &amp;min_height,
13973  *                                           &amp;natural_height);
13974  *       height = CLAMP (natural_height, min_height, available_height);
13975  *
13976  *       clutter_actor_get_preferred_width (self, height,
13977  *                                          &amp;min_width,
13978  *                                          &amp;natural_width);
13979  *       width = CLAMP (natural_width, min_width, available_width);
13980  *     }
13981  *
13982  *   box.x1 = x; box.y1 = y;
13983  *   box.x2 = box.x1 + available_width;
13984  *   box.y2 = box.y1 + available_height;
13985  *   clutter_actor_allocate (self, &amp;box, flags);
13986  * ]|
13987  *
13988  * This function can be used by fluid layout managers to allocate
13989  * an actor's preferred size without making it bigger than the area
13990  * available for the container.
13991  *
13992  * Since: 1.0
13993  */
13994 void
13995 clutter_actor_allocate_available_size (ClutterActor           *self,
13996                                        gfloat                  x,
13997                                        gfloat                  y,
13998                                        gfloat                  available_width,
13999                                        gfloat                  available_height,
14000                                        ClutterAllocationFlags  flags)
14001 {
14002   ClutterActorPrivate *priv;
14003   gfloat width, height;
14004   gfloat min_width, min_height;
14005   gfloat natural_width, natural_height;
14006   ClutterActorBox box;
14007
14008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14009
14010   priv = self->priv;
14011
14012   width = height = 0.0;
14013
14014   switch (priv->request_mode)
14015     {
14016     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
14017       clutter_actor_get_preferred_width (self, available_height,
14018                                          &min_width,
14019                                          &natural_width);
14020       width  = CLAMP (natural_width, min_width, available_width);
14021
14022       clutter_actor_get_preferred_height (self, width,
14023                                           &min_height,
14024                                           &natural_height);
14025       height = CLAMP (natural_height, min_height, available_height);
14026       break;
14027
14028     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
14029       clutter_actor_get_preferred_height (self, available_width,
14030                                           &min_height,
14031                                           &natural_height);
14032       height = CLAMP (natural_height, min_height, available_height);
14033
14034       clutter_actor_get_preferred_width (self, height,
14035                                          &min_width,
14036                                          &natural_width);
14037       width  = CLAMP (natural_width, min_width, available_width);
14038       break;
14039     }
14040
14041
14042   box.x1 = x;
14043   box.y1 = y;
14044   box.x2 = box.x1 + width;
14045   box.y2 = box.y1 + height;
14046   clutter_actor_allocate (self, &box, flags);
14047 }
14048
14049 /**
14050  * clutter_actor_allocate_preferred_size:
14051  * @self: a #ClutterActor
14052  * @flags: flags controlling the allocation
14053  *
14054  * Allocates the natural size of @self.
14055  *
14056  * This function is a utility call for #ClutterActor implementations
14057  * that allocates the actor's preferred natural size. It can be used
14058  * by fixed layout managers (like #ClutterGroup or so called
14059  * 'composite actors') inside the ClutterActor::allocate
14060  * implementation to give each child exactly how much space it
14061  * requires.
14062  *
14063  * This function is not meant to be used by applications. It is also
14064  * not meant to be used outside the implementation of the
14065  * ClutterActor::allocate virtual function.
14066  *
14067  * Since: 0.8
14068  */
14069 void
14070 clutter_actor_allocate_preferred_size (ClutterActor           *self,
14071                                        ClutterAllocationFlags  flags)
14072 {
14073   gfloat actor_x, actor_y;
14074   gfloat natural_width, natural_height;
14075   ClutterActorBox actor_box;
14076
14077   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14078
14079   actor_x = clutter_actor_get_x (self);
14080   actor_y = clutter_actor_get_y (self);
14081
14082   clutter_actor_get_preferred_size (self,
14083                                     NULL, NULL,
14084                                     &natural_width,
14085                                     &natural_height);
14086
14087   actor_box.x1 = actor_x;
14088   actor_box.y1 = actor_y;
14089   actor_box.x2 = actor_box.x1 + natural_width;
14090   actor_box.y2 = actor_box.y1 + natural_height;
14091
14092   clutter_actor_allocate (self, &actor_box, flags);
14093 }
14094
14095 /**
14096  * clutter_actor_allocate_align_fill:
14097  * @self: a #ClutterActor
14098  * @box: a #ClutterActorBox, containing the available width and height
14099  * @x_align: the horizontal alignment, between 0 and 1
14100  * @y_align: the vertical alignment, between 0 and 1
14101  * @x_fill: whether the actor should fill horizontally
14102  * @y_fill: whether the actor should fill vertically
14103  * @flags: allocation flags to be passed to clutter_actor_allocate()
14104  *
14105  * Allocates @self by taking into consideration the available allocation
14106  * area; an alignment factor on either axis; and whether the actor should
14107  * fill the allocation on either axis.
14108  *
14109  * The @box should contain the available allocation width and height;
14110  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14111  * allocation will be offset by their value.
14112  *
14113  * This function takes into consideration the geometry request specified by
14114  * the #ClutterActor:request-mode property, and the text direction.
14115  *
14116  * This function is useful for fluid layout managers, like #ClutterBinLayout
14117  * or #ClutterTableLayout
14118  *
14119  * Since: 1.4
14120  */
14121 void
14122 clutter_actor_allocate_align_fill (ClutterActor           *self,
14123                                    const ClutterActorBox  *box,
14124                                    gdouble                 x_align,
14125                                    gdouble                 y_align,
14126                                    gboolean                x_fill,
14127                                    gboolean                y_fill,
14128                                    ClutterAllocationFlags  flags)
14129 {
14130   ClutterActorPrivate *priv;
14131   ClutterActorBox allocation = { 0, };
14132   gfloat x_offset, y_offset;
14133   gfloat available_width, available_height;
14134   gfloat child_width, child_height;
14135
14136   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14137   g_return_if_fail (box != NULL);
14138   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14139   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14140
14141   priv = self->priv;
14142
14143   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14144   clutter_actor_box_get_size (box, &available_width, &available_height);
14145
14146   if (available_width < 0)
14147     available_width = 0;
14148
14149   if (available_height < 0)
14150     available_height = 0;
14151
14152   if (x_fill)
14153     {
14154       allocation.x1 = x_offset;
14155       allocation.x2 = allocation.x1 + available_width;
14156     }
14157
14158   if (y_fill)
14159     {
14160       allocation.y1 = y_offset;
14161       allocation.y2 = allocation.y1 + available_height;
14162     }
14163
14164   /* if we are filling horizontally and vertically then we're done */
14165   if (x_fill && y_fill)
14166     goto out;
14167
14168   child_width = child_height = 0.0f;
14169
14170   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14171     {
14172       gfloat min_width, natural_width;
14173       gfloat min_height, natural_height;
14174
14175       clutter_actor_get_preferred_width (self, available_height,
14176                                          &min_width,
14177                                          &natural_width);
14178
14179       child_width = CLAMP (natural_width, min_width, available_width);
14180
14181       if (!y_fill)
14182         {
14183           clutter_actor_get_preferred_height (self, child_width,
14184                                               &min_height,
14185                                               &natural_height);
14186
14187           child_height = CLAMP (natural_height, min_height, available_height);
14188         }
14189     }
14190   else
14191     {
14192       gfloat min_width, natural_width;
14193       gfloat min_height, natural_height;
14194
14195       clutter_actor_get_preferred_height (self, available_width,
14196                                           &min_height,
14197                                           &natural_height);
14198
14199       child_height = CLAMP (natural_height, min_height, available_height);
14200
14201       if (!x_fill)
14202         {
14203           clutter_actor_get_preferred_width (self, child_height,
14204                                              &min_width,
14205                                              &natural_width);
14206
14207           child_width = CLAMP (natural_width, min_width, available_width);
14208         }
14209     }
14210
14211   /* invert the horizontal alignment for RTL languages */
14212   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14213     x_align = 1.0 - x_align;
14214
14215   if (!x_fill)
14216     {
14217       allocation.x1 = x_offset
14218                     + ((available_width - child_width) * x_align);
14219       allocation.x2 = allocation.x1 + child_width;
14220     }
14221
14222   if (!y_fill)
14223     {
14224       allocation.y1 = y_offset
14225                     + ((available_height - child_height) * y_align);
14226       allocation.y2 = allocation.y1 + child_height;
14227     }
14228
14229 out:
14230   clutter_actor_box_clamp_to_pixel (&allocation);
14231   clutter_actor_allocate (self, &allocation, flags);
14232 }
14233
14234 /**
14235  * clutter_actor_grab_key_focus:
14236  * @self: a #ClutterActor
14237  *
14238  * Sets the key focus of the #ClutterStage including @self
14239  * to this #ClutterActor.
14240  *
14241  * Since: 1.0
14242  */
14243 void
14244 clutter_actor_grab_key_focus (ClutterActor *self)
14245 {
14246   ClutterActor *stage;
14247
14248   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14249
14250   stage = _clutter_actor_get_stage_internal (self);
14251   if (stage != NULL)
14252     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14253 }
14254
14255 /**
14256  * clutter_actor_get_pango_context:
14257  * @self: a #ClutterActor
14258  *
14259  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14260  * is already configured using the appropriate font map, resolution
14261  * and font options.
14262  *
14263  * Unlike clutter_actor_create_pango_context(), this context is owend
14264  * by the #ClutterActor and it will be updated each time the options
14265  * stored by the #ClutterBackend change.
14266  *
14267  * You can use the returned #PangoContext to create a #PangoLayout
14268  * and render text using cogl_pango_render_layout() to reuse the
14269  * glyphs cache also used by Clutter.
14270  *
14271  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14272  *   The returned #PangoContext is owned by the actor and should not be
14273  *   unreferenced by the application code
14274  *
14275  * Since: 1.0
14276  */
14277 PangoContext *
14278 clutter_actor_get_pango_context (ClutterActor *self)
14279 {
14280   ClutterActorPrivate *priv;
14281
14282   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14283
14284   priv = self->priv;
14285
14286   if (priv->pango_context != NULL)
14287     return priv->pango_context;
14288
14289   priv->pango_context = _clutter_context_get_pango_context ();
14290   g_object_ref (priv->pango_context);
14291
14292   return priv->pango_context;
14293 }
14294
14295 /**
14296  * clutter_actor_create_pango_context:
14297  * @self: a #ClutterActor
14298  *
14299  * Creates a #PangoContext for the given actor. The #PangoContext
14300  * is already configured using the appropriate font map, resolution
14301  * and font options.
14302  *
14303  * See also clutter_actor_get_pango_context().
14304  *
14305  * Return value: (transfer full): the newly created #PangoContext.
14306  *   Use g_object_unref() on the returned value to deallocate its
14307  *   resources
14308  *
14309  * Since: 1.0
14310  */
14311 PangoContext *
14312 clutter_actor_create_pango_context (ClutterActor *self)
14313 {
14314   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14315
14316   return _clutter_context_create_pango_context ();
14317 }
14318
14319 /**
14320  * clutter_actor_create_pango_layout:
14321  * @self: a #ClutterActor
14322  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14323  *
14324  * Creates a new #PangoLayout from the same #PangoContext used
14325  * by the #ClutterActor. The #PangoLayout is already configured
14326  * with the font map, resolution and font options, and the
14327  * given @text.
14328  *
14329  * If you want to keep around a #PangoLayout created by this
14330  * function you will have to connect to the #ClutterBackend::font-changed
14331  * and #ClutterBackend::resolution-changed signals, and call
14332  * pango_layout_context_changed() in response to them.
14333  *
14334  * Return value: (transfer full): the newly created #PangoLayout.
14335  *   Use g_object_unref() when done
14336  *
14337  * Since: 1.0
14338  */
14339 PangoLayout *
14340 clutter_actor_create_pango_layout (ClutterActor *self,
14341                                    const gchar  *text)
14342 {
14343   PangoContext *context;
14344   PangoLayout *layout;
14345
14346   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14347
14348   context = clutter_actor_get_pango_context (self);
14349   layout = pango_layout_new (context);
14350
14351   if (text)
14352     pango_layout_set_text (layout, text, -1);
14353
14354   return layout;
14355 }
14356
14357 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14358  * ClutterOffscreenEffect.
14359  */
14360 void
14361 _clutter_actor_set_opacity_override (ClutterActor *self,
14362                                      gint          opacity)
14363 {
14364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14365
14366   self->priv->opacity_override = opacity;
14367 }
14368
14369 gint
14370 _clutter_actor_get_opacity_override (ClutterActor *self)
14371 {
14372   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14373
14374   return self->priv->opacity_override;
14375 }
14376
14377 /* Allows you to disable applying the actors model view transform during
14378  * a paint. Used by ClutterClone. */
14379 void
14380 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14381                                                 gboolean      enable)
14382 {
14383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14384
14385   self->priv->enable_model_view_transform = enable;
14386 }
14387
14388 void
14389 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14390                                           gboolean      enable)
14391 {
14392   ClutterActorPrivate *priv;
14393
14394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14395
14396   priv = self->priv;
14397
14398   priv->enable_paint_unmapped = enable;
14399
14400   if (priv->enable_paint_unmapped)
14401     {
14402       /* Make sure that the parents of the widget are realized first;
14403        * otherwise checks in clutter_actor_update_map_state() will
14404        * fail.
14405        */
14406       clutter_actor_realize (self);
14407
14408       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14409     }
14410   else
14411     {
14412       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14413     }
14414 }
14415
14416 static void
14417 clutter_anchor_coord_get_units (ClutterActor      *self,
14418                                 const AnchorCoord *coord,
14419                                 gfloat            *x,
14420                                 gfloat            *y,
14421                                 gfloat            *z)
14422 {
14423   if (coord->is_fractional)
14424     {
14425       gfloat actor_width, actor_height;
14426
14427       clutter_actor_get_size (self, &actor_width, &actor_height);
14428
14429       if (x)
14430         *x = actor_width * coord->v.fraction.x;
14431
14432       if (y)
14433         *y = actor_height * coord->v.fraction.y;
14434
14435       if (z)
14436         *z = 0;
14437     }
14438   else
14439     {
14440       if (x)
14441         *x = coord->v.units.x;
14442
14443       if (y)
14444         *y = coord->v.units.y;
14445
14446       if (z)
14447         *z = coord->v.units.z;
14448     }
14449 }
14450
14451 static void
14452 clutter_anchor_coord_set_units (AnchorCoord *coord,
14453                                 gfloat       x,
14454                                 gfloat       y,
14455                                 gfloat       z)
14456 {
14457   coord->is_fractional = FALSE;
14458   coord->v.units.x = x;
14459   coord->v.units.y = y;
14460   coord->v.units.z = z;
14461 }
14462
14463 static ClutterGravity
14464 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14465 {
14466   if (coord->is_fractional)
14467     {
14468       if (coord->v.fraction.x == 0.0)
14469         {
14470           if (coord->v.fraction.y == 0.0)
14471             return CLUTTER_GRAVITY_NORTH_WEST;
14472           else if (coord->v.fraction.y == 0.5)
14473             return CLUTTER_GRAVITY_WEST;
14474           else if (coord->v.fraction.y == 1.0)
14475             return CLUTTER_GRAVITY_SOUTH_WEST;
14476           else
14477             return CLUTTER_GRAVITY_NONE;
14478         }
14479       else if (coord->v.fraction.x == 0.5)
14480         {
14481           if (coord->v.fraction.y == 0.0)
14482             return CLUTTER_GRAVITY_NORTH;
14483           else if (coord->v.fraction.y == 0.5)
14484             return CLUTTER_GRAVITY_CENTER;
14485           else if (coord->v.fraction.y == 1.0)
14486             return CLUTTER_GRAVITY_SOUTH;
14487           else
14488             return CLUTTER_GRAVITY_NONE;
14489         }
14490       else if (coord->v.fraction.x == 1.0)
14491         {
14492           if (coord->v.fraction.y == 0.0)
14493             return CLUTTER_GRAVITY_NORTH_EAST;
14494           else if (coord->v.fraction.y == 0.5)
14495             return CLUTTER_GRAVITY_EAST;
14496           else if (coord->v.fraction.y == 1.0)
14497             return CLUTTER_GRAVITY_SOUTH_EAST;
14498           else
14499             return CLUTTER_GRAVITY_NONE;
14500         }
14501       else
14502         return CLUTTER_GRAVITY_NONE;
14503     }
14504   else
14505     return CLUTTER_GRAVITY_NONE;
14506 }
14507
14508 static void
14509 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14510                                   ClutterGravity  gravity)
14511 {
14512   switch (gravity)
14513     {
14514     case CLUTTER_GRAVITY_NORTH:
14515       coord->v.fraction.x = 0.5;
14516       coord->v.fraction.y = 0.0;
14517       break;
14518
14519     case CLUTTER_GRAVITY_NORTH_EAST:
14520       coord->v.fraction.x = 1.0;
14521       coord->v.fraction.y = 0.0;
14522       break;
14523
14524     case CLUTTER_GRAVITY_EAST:
14525       coord->v.fraction.x = 1.0;
14526       coord->v.fraction.y = 0.5;
14527       break;
14528
14529     case CLUTTER_GRAVITY_SOUTH_EAST:
14530       coord->v.fraction.x = 1.0;
14531       coord->v.fraction.y = 1.0;
14532       break;
14533
14534     case CLUTTER_GRAVITY_SOUTH:
14535       coord->v.fraction.x = 0.5;
14536       coord->v.fraction.y = 1.0;
14537       break;
14538
14539     case CLUTTER_GRAVITY_SOUTH_WEST:
14540       coord->v.fraction.x = 0.0;
14541       coord->v.fraction.y = 1.0;
14542       break;
14543
14544     case CLUTTER_GRAVITY_WEST:
14545       coord->v.fraction.x = 0.0;
14546       coord->v.fraction.y = 0.5;
14547       break;
14548
14549     case CLUTTER_GRAVITY_NORTH_WEST:
14550       coord->v.fraction.x = 0.0;
14551       coord->v.fraction.y = 0.0;
14552       break;
14553
14554     case CLUTTER_GRAVITY_CENTER:
14555       coord->v.fraction.x = 0.5;
14556       coord->v.fraction.y = 0.5;
14557       break;
14558
14559     default:
14560       coord->v.fraction.x = 0.0;
14561       coord->v.fraction.y = 0.0;
14562       break;
14563     }
14564
14565   coord->is_fractional = TRUE;
14566 }
14567
14568 static gboolean
14569 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14570 {
14571   if (coord->is_fractional)
14572     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14573   else
14574     return (coord->v.units.x == 0.0
14575             && coord->v.units.y == 0.0
14576             && coord->v.units.z == 0.0);
14577 }
14578
14579 /**
14580  * clutter_actor_get_flags:
14581  * @self: a #ClutterActor
14582  *
14583  * Retrieves the flags set on @self
14584  *
14585  * Return value: a bitwise or of #ClutterActorFlags or 0
14586  *
14587  * Since: 1.0
14588  */
14589 ClutterActorFlags
14590 clutter_actor_get_flags (ClutterActor *self)
14591 {
14592   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14593
14594   return self->flags;
14595 }
14596
14597 /**
14598  * clutter_actor_set_flags:
14599  * @self: a #ClutterActor
14600  * @flags: the flags to set
14601  *
14602  * Sets @flags on @self
14603  *
14604  * This function will emit notifications for the changed properties
14605  *
14606  * Since: 1.0
14607  */
14608 void
14609 clutter_actor_set_flags (ClutterActor      *self,
14610                          ClutterActorFlags  flags)
14611 {
14612   ClutterActorFlags old_flags;
14613   GObject *obj;
14614   gboolean was_reactive_set, reactive_set;
14615   gboolean was_realized_set, realized_set;
14616   gboolean was_mapped_set, mapped_set;
14617   gboolean was_visible_set, visible_set;
14618
14619   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14620
14621   if (self->flags == flags)
14622     return;
14623
14624   obj = G_OBJECT (self);
14625   g_object_ref (obj);
14626   g_object_freeze_notify (obj);
14627
14628   old_flags = self->flags;
14629
14630   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14631   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14632   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14633   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14634
14635   self->flags |= flags;
14636
14637   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14638   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14639   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14640   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14641
14642   if (reactive_set != was_reactive_set)
14643     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14644
14645   if (realized_set != was_realized_set)
14646     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14647
14648   if (mapped_set != was_mapped_set)
14649     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14650
14651   if (visible_set != was_visible_set)
14652     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14653
14654   g_object_thaw_notify (obj);
14655   g_object_unref (obj);
14656 }
14657
14658 /**
14659  * clutter_actor_unset_flags:
14660  * @self: a #ClutterActor
14661  * @flags: the flags to unset
14662  *
14663  * Unsets @flags on @self
14664  *
14665  * This function will emit notifications for the changed properties
14666  *
14667  * Since: 1.0
14668  */
14669 void
14670 clutter_actor_unset_flags (ClutterActor      *self,
14671                            ClutterActorFlags  flags)
14672 {
14673   ClutterActorFlags old_flags;
14674   GObject *obj;
14675   gboolean was_reactive_set, reactive_set;
14676   gboolean was_realized_set, realized_set;
14677   gboolean was_mapped_set, mapped_set;
14678   gboolean was_visible_set, visible_set;
14679
14680   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14681
14682   obj = G_OBJECT (self);
14683   g_object_freeze_notify (obj);
14684
14685   old_flags = self->flags;
14686
14687   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14688   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14689   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14690   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14691
14692   self->flags &= ~flags;
14693
14694   if (self->flags == old_flags)
14695     return;
14696
14697   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14698   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14699   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14700   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14701
14702   if (reactive_set != was_reactive_set)
14703     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14704
14705   if (realized_set != was_realized_set)
14706     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14707
14708   if (mapped_set != was_mapped_set)
14709     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14710
14711   if (visible_set != was_visible_set)
14712     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14713
14714   g_object_thaw_notify (obj);
14715 }
14716
14717 /**
14718  * clutter_actor_get_transformation_matrix:
14719  * @self: a #ClutterActor
14720  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14721  *
14722  * Retrieves the transformations applied to @self relative to its
14723  * parent.
14724  *
14725  * Since: 1.0
14726  */
14727 void
14728 clutter_actor_get_transformation_matrix (ClutterActor *self,
14729                                          CoglMatrix   *matrix)
14730 {
14731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14732
14733   cogl_matrix_init_identity (matrix);
14734
14735   _clutter_actor_apply_modelview_transform (self, matrix);
14736 }
14737
14738 void
14739 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14740                                    gboolean      is_in_clone_paint)
14741 {
14742   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14743   self->priv->in_clone_paint = is_in_clone_paint;
14744 }
14745
14746 /**
14747  * clutter_actor_is_in_clone_paint:
14748  * @self: a #ClutterActor
14749  *
14750  * Checks whether @self is being currently painted by a #ClutterClone
14751  *
14752  * This function is useful only inside the ::paint virtual function
14753  * implementations or within handlers for the #ClutterActor::paint
14754  * signal
14755  *
14756  * This function should not be used by applications
14757  *
14758  * Return value: %TRUE if the #ClutterActor is currently being painted
14759  *   by a #ClutterClone, and %FALSE otherwise
14760  *
14761  * Since: 1.0
14762  */
14763 gboolean
14764 clutter_actor_is_in_clone_paint (ClutterActor *self)
14765 {
14766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14767
14768   return self->priv->in_clone_paint;
14769 }
14770
14771 static gboolean
14772 set_direction_recursive (ClutterActor *actor,
14773                          gpointer      user_data)
14774 {
14775   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14776
14777   clutter_actor_set_text_direction (actor, text_dir);
14778
14779   return TRUE;
14780 }
14781
14782 /**
14783  * clutter_actor_set_text_direction:
14784  * @self: a #ClutterActor
14785  * @text_dir: the text direction for @self
14786  *
14787  * Sets the #ClutterTextDirection for an actor
14788  *
14789  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14790  *
14791  * If @self implements #ClutterContainer then this function will recurse
14792  * inside all the children of @self (including the internal ones).
14793  *
14794  * Composite actors not implementing #ClutterContainer, or actors requiring
14795  * special handling when the text direction changes, should connect to
14796  * the #GObject::notify signal for the #ClutterActor:text-direction property
14797  *
14798  * Since: 1.2
14799  */
14800 void
14801 clutter_actor_set_text_direction (ClutterActor         *self,
14802                                   ClutterTextDirection  text_dir)
14803 {
14804   ClutterActorPrivate *priv;
14805
14806   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14807   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14808
14809   priv = self->priv;
14810
14811   if (priv->text_direction != text_dir)
14812     {
14813       priv->text_direction = text_dir;
14814
14815       /* we need to emit the notify::text-direction first, so that
14816        * the sub-classes can catch that and do specific handling of
14817        * the text direction; see clutter_text_direction_changed_cb()
14818        * inside clutter-text.c
14819        */
14820       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14821
14822       _clutter_actor_foreach_child (self, set_direction_recursive,
14823                                     GINT_TO_POINTER (text_dir));
14824
14825       clutter_actor_queue_relayout (self);
14826     }
14827 }
14828
14829 void
14830 _clutter_actor_set_has_pointer (ClutterActor *self,
14831                                 gboolean      has_pointer)
14832 {
14833   ClutterActorPrivate *priv = self->priv;
14834
14835   if (priv->has_pointer != has_pointer)
14836     {
14837       priv->has_pointer = has_pointer;
14838
14839       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14840     }
14841 }
14842
14843 /**
14844  * clutter_actor_get_text_direction:
14845  * @self: a #ClutterActor
14846  *
14847  * Retrieves the value set using clutter_actor_set_text_direction()
14848  *
14849  * If no text direction has been previously set, the default text
14850  * direction, as returned by clutter_get_default_text_direction(), will
14851  * be returned instead
14852  *
14853  * Return value: the #ClutterTextDirection for the actor
14854  *
14855  * Since: 1.2
14856  */
14857 ClutterTextDirection
14858 clutter_actor_get_text_direction (ClutterActor *self)
14859 {
14860   ClutterActorPrivate *priv;
14861
14862   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14863                         CLUTTER_TEXT_DIRECTION_LTR);
14864
14865   priv = self->priv;
14866
14867   /* if no direction has been set yet use the default */
14868   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14869     priv->text_direction = clutter_get_default_text_direction ();
14870
14871   return priv->text_direction;
14872 }
14873
14874 /**
14875  * clutter_actor_push_internal:
14876  * @self: a #ClutterActor
14877  *
14878  * Should be used by actors implementing the #ClutterContainer and with
14879  * internal children added through clutter_actor_set_parent(), for instance:
14880  *
14881  * |[
14882  *   static void
14883  *   my_actor_init (MyActor *self)
14884  *   {
14885  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14886  *
14887  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14888  *
14889  *     /&ast; calling clutter_actor_set_parent() now will result in
14890  *      &ast; the internal flag being set on a child of MyActor
14891  *      &ast;/
14892  *
14893  *     /&ast; internal child - a background texture &ast;/
14894  *     self->priv->background_tex = clutter_texture_new ();
14895  *     clutter_actor_set_parent (self->priv->background_tex,
14896  *                               CLUTTER_ACTOR (self));
14897  *
14898  *     /&ast; internal child - a label &ast;/
14899  *     self->priv->label = clutter_text_new ();
14900  *     clutter_actor_set_parent (self->priv->label,
14901  *                               CLUTTER_ACTOR (self));
14902  *
14903  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14904  *
14905  *     /&ast; calling clutter_actor_set_parent() now will not result in
14906  *      &ast; the internal flag being set on a child of MyActor
14907  *      &ast;/
14908  *   }
14909  * ]|
14910  *
14911  * This function will be used by Clutter to toggle an "internal child"
14912  * flag whenever clutter_actor_set_parent() is called; internal children
14913  * are handled differently by Clutter, specifically when destroying their
14914  * parent.
14915  *
14916  * Call clutter_actor_pop_internal() when you finished adding internal
14917  * children.
14918  *
14919  * Nested calls to clutter_actor_push_internal() are allowed, but each
14920  * one must by followed by a clutter_actor_pop_internal() call.
14921  *
14922  * Since: 1.2
14923  *
14924  * Deprecated: 1.10: All children of an actor are accessible through
14925  *   the #ClutterActor API, and #ClutterActor implements the
14926  *   #ClutterContainer interface, so this function is only useful
14927  *   for legacy containers overriding the default implementation.
14928  */
14929 void
14930 clutter_actor_push_internal (ClutterActor *self)
14931 {
14932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14933
14934   self->priv->internal_child += 1;
14935 }
14936
14937 /**
14938  * clutter_actor_pop_internal:
14939  * @self: a #ClutterActor
14940  *
14941  * Disables the effects of clutter_actor_push_internal().
14942  *
14943  * Since: 1.2
14944  *
14945  * Deprecated: 1.10: All children of an actor are accessible through
14946  *   the #ClutterActor API. This function is only useful for legacy
14947  *   containers overriding the default implementation of the
14948  *   #ClutterContainer interface.
14949  */
14950 void
14951 clutter_actor_pop_internal (ClutterActor *self)
14952 {
14953   ClutterActorPrivate *priv;
14954
14955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956
14957   priv = self->priv;
14958
14959   if (priv->internal_child == 0)
14960     {
14961       g_warning ("Mismatched %s: you need to call "
14962                  "clutter_actor_push_composite() at least once before "
14963                  "calling this function", G_STRFUNC);
14964       return;
14965     }
14966
14967   priv->internal_child -= 1;
14968 }
14969
14970 /**
14971  * clutter_actor_has_pointer:
14972  * @self: a #ClutterActor
14973  *
14974  * Checks whether an actor contains the pointer of a
14975  * #ClutterInputDevice
14976  *
14977  * Return value: %TRUE if the actor contains the pointer, and
14978  *   %FALSE otherwise
14979  *
14980  * Since: 1.2
14981  */
14982 gboolean
14983 clutter_actor_has_pointer (ClutterActor *self)
14984 {
14985   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14986
14987   return self->priv->has_pointer;
14988 }
14989
14990 /* XXX: This is a workaround for not being able to break the ABI of
14991  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14992  * clutter_actor_queue_clipped_redraw() for details.
14993  */
14994 ClutterPaintVolume *
14995 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14996 {
14997   return g_object_get_data (G_OBJECT (self),
14998                             "-clutter-actor-queue-redraw-clip");
14999 }
15000
15001 void
15002 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
15003                                       ClutterPaintVolume *clip)
15004 {
15005   g_object_set_data (G_OBJECT (self),
15006                      "-clutter-actor-queue-redraw-clip",
15007                      clip);
15008 }
15009
15010 /**
15011  * clutter_actor_has_allocation:
15012  * @self: a #ClutterActor
15013  *
15014  * Checks if the actor has an up-to-date allocation assigned to
15015  * it. This means that the actor should have an allocation: it's
15016  * visible and has a parent. It also means that there is no
15017  * outstanding relayout request in progress for the actor or its
15018  * children (There might be other outstanding layout requests in
15019  * progress that will cause the actor to get a new allocation
15020  * when the stage is laid out, however).
15021  *
15022  * If this function returns %FALSE, then the actor will normally
15023  * be allocated before it is next drawn on the screen.
15024  *
15025  * Return value: %TRUE if the actor has an up-to-date allocation
15026  *
15027  * Since: 1.4
15028  */
15029 gboolean
15030 clutter_actor_has_allocation (ClutterActor *self)
15031 {
15032   ClutterActorPrivate *priv;
15033
15034   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15035
15036   priv = self->priv;
15037
15038   return priv->parent != NULL &&
15039          CLUTTER_ACTOR_IS_VISIBLE (self) &&
15040          !priv->needs_allocation;
15041 }
15042
15043 /**
15044  * clutter_actor_add_action:
15045  * @self: a #ClutterActor
15046  * @action: a #ClutterAction
15047  *
15048  * Adds @action to the list of actions applied to @self
15049  *
15050  * A #ClutterAction can only belong to one actor at a time
15051  *
15052  * The #ClutterActor will hold a reference on @action until either
15053  * clutter_actor_remove_action() or clutter_actor_clear_actions()
15054  * is called
15055  *
15056  * Since: 1.4
15057  */
15058 void
15059 clutter_actor_add_action (ClutterActor  *self,
15060                           ClutterAction *action)
15061 {
15062   ClutterActorPrivate *priv;
15063
15064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15065   g_return_if_fail (CLUTTER_IS_ACTION (action));
15066
15067   priv = self->priv;
15068
15069   if (priv->actions == NULL)
15070     {
15071       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15072       priv->actions->actor = self;
15073     }
15074
15075   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15076
15077   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15078 }
15079
15080 /**
15081  * clutter_actor_add_action_with_name:
15082  * @self: a #ClutterActor
15083  * @name: the name to set on the action
15084  * @action: a #ClutterAction
15085  *
15086  * A convenience function for setting the name of a #ClutterAction
15087  * while adding it to the list of actions applied to @self
15088  *
15089  * This function is the logical equivalent of:
15090  *
15091  * |[
15092  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15093  *   clutter_actor_add_action (self, action);
15094  * ]|
15095  *
15096  * Since: 1.4
15097  */
15098 void
15099 clutter_actor_add_action_with_name (ClutterActor  *self,
15100                                     const gchar   *name,
15101                                     ClutterAction *action)
15102 {
15103   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15104   g_return_if_fail (name != NULL);
15105   g_return_if_fail (CLUTTER_IS_ACTION (action));
15106
15107   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15108   clutter_actor_add_action (self, action);
15109 }
15110
15111 /**
15112  * clutter_actor_remove_action:
15113  * @self: a #ClutterActor
15114  * @action: a #ClutterAction
15115  *
15116  * Removes @action from the list of actions applied to @self
15117  *
15118  * The reference held by @self on the #ClutterAction will be released
15119  *
15120  * Since: 1.4
15121  */
15122 void
15123 clutter_actor_remove_action (ClutterActor  *self,
15124                              ClutterAction *action)
15125 {
15126   ClutterActorPrivate *priv;
15127
15128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15129   g_return_if_fail (CLUTTER_IS_ACTION (action));
15130
15131   priv = self->priv;
15132
15133   if (priv->actions == NULL)
15134     return;
15135
15136   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15137
15138   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15139     g_clear_object (&priv->actions);
15140
15141   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15142 }
15143
15144 /**
15145  * clutter_actor_remove_action_by_name:
15146  * @self: a #ClutterActor
15147  * @name: the name of the action to remove
15148  *
15149  * Removes the #ClutterAction with the given name from the list
15150  * of actions applied to @self
15151  *
15152  * Since: 1.4
15153  */
15154 void
15155 clutter_actor_remove_action_by_name (ClutterActor *self,
15156                                      const gchar  *name)
15157 {
15158   ClutterActorPrivate *priv;
15159   ClutterActorMeta *meta;
15160
15161   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15162   g_return_if_fail (name != NULL);
15163
15164   priv = self->priv;
15165
15166   if (priv->actions == NULL)
15167     return;
15168
15169   meta = _clutter_meta_group_get_meta (priv->actions, name);
15170   if (meta == NULL)
15171     return;
15172
15173   _clutter_meta_group_remove_meta (priv->actions, meta);
15174
15175   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15176 }
15177
15178 /**
15179  * clutter_actor_get_actions:
15180  * @self: a #ClutterActor
15181  *
15182  * Retrieves the list of actions applied to @self
15183  *
15184  * Return value: (transfer container) (element-type Clutter.Action): a copy
15185  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
15186  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15187  *   allocated by the returned #GList
15188  *
15189  * Since: 1.4
15190  */
15191 GList *
15192 clutter_actor_get_actions (ClutterActor *self)
15193 {
15194   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15195
15196   if (self->priv->actions == NULL)
15197     return NULL;
15198
15199   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15200 }
15201
15202 /**
15203  * clutter_actor_get_action:
15204  * @self: a #ClutterActor
15205  * @name: the name of the action to retrieve
15206  *
15207  * Retrieves the #ClutterAction with the given name in the list
15208  * of actions applied to @self
15209  *
15210  * Return value: (transfer none): a #ClutterAction for the given
15211  *   name, or %NULL. The returned #ClutterAction is owned by the
15212  *   actor and it should not be unreferenced directly
15213  *
15214  * Since: 1.4
15215  */
15216 ClutterAction *
15217 clutter_actor_get_action (ClutterActor *self,
15218                           const gchar  *name)
15219 {
15220   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15221   g_return_val_if_fail (name != NULL, NULL);
15222
15223   if (self->priv->actions == NULL)
15224     return NULL;
15225
15226   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15227 }
15228
15229 /**
15230  * clutter_actor_clear_actions:
15231  * @self: a #ClutterActor
15232  *
15233  * Clears the list of actions applied to @self
15234  *
15235  * Since: 1.4
15236  */
15237 void
15238 clutter_actor_clear_actions (ClutterActor *self)
15239 {
15240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15241
15242   if (self->priv->actions == NULL)
15243     return;
15244
15245   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15246 }
15247
15248 /**
15249  * clutter_actor_add_constraint:
15250  * @self: a #ClutterActor
15251  * @constraint: a #ClutterConstraint
15252  *
15253  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15254  * to @self
15255  *
15256  * The #ClutterActor will hold a reference on the @constraint until
15257  * either clutter_actor_remove_constraint() or
15258  * clutter_actor_clear_constraints() is called.
15259  *
15260  * Since: 1.4
15261  */
15262 void
15263 clutter_actor_add_constraint (ClutterActor      *self,
15264                               ClutterConstraint *constraint)
15265 {
15266   ClutterActorPrivate *priv;
15267
15268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15269   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15270
15271   priv = self->priv;
15272
15273   if (priv->constraints == NULL)
15274     {
15275       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15276       priv->constraints->actor = self;
15277     }
15278
15279   _clutter_meta_group_add_meta (priv->constraints,
15280                                 CLUTTER_ACTOR_META (constraint));
15281   clutter_actor_queue_relayout (self);
15282
15283   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15284 }
15285
15286 /**
15287  * clutter_actor_add_constraint_with_name:
15288  * @self: a #ClutterActor
15289  * @name: the name to set on the constraint
15290  * @constraint: a #ClutterConstraint
15291  *
15292  * A convenience function for setting the name of a #ClutterConstraint
15293  * while adding it to the list of constraints applied to @self
15294  *
15295  * This function is the logical equivalent of:
15296  *
15297  * |[
15298  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15299  *   clutter_actor_add_constraint (self, constraint);
15300  * ]|
15301  *
15302  * Since: 1.4
15303  */
15304 void
15305 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15306                                         const gchar       *name,
15307                                         ClutterConstraint *constraint)
15308 {
15309   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15310   g_return_if_fail (name != NULL);
15311   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15312
15313   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15314   clutter_actor_add_constraint (self, constraint);
15315 }
15316
15317 /**
15318  * clutter_actor_remove_constraint:
15319  * @self: a #ClutterActor
15320  * @constraint: a #ClutterConstraint
15321  *
15322  * Removes @constraint from the list of constraints applied to @self
15323  *
15324  * The reference held by @self on the #ClutterConstraint will be released
15325  *
15326  * Since: 1.4
15327  */
15328 void
15329 clutter_actor_remove_constraint (ClutterActor      *self,
15330                                  ClutterConstraint *constraint)
15331 {
15332   ClutterActorPrivate *priv;
15333
15334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15335   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15336
15337   priv = self->priv;
15338
15339   if (priv->constraints == NULL)
15340     return;
15341
15342   _clutter_meta_group_remove_meta (priv->constraints,
15343                                    CLUTTER_ACTOR_META (constraint));
15344
15345   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15346     g_clear_object (&priv->constraints);
15347
15348   clutter_actor_queue_relayout (self);
15349
15350   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15351 }
15352
15353 /**
15354  * clutter_actor_remove_constraint_by_name:
15355  * @self: a #ClutterActor
15356  * @name: the name of the constraint to remove
15357  *
15358  * Removes the #ClutterConstraint with the given name from the list
15359  * of constraints applied to @self
15360  *
15361  * Since: 1.4
15362  */
15363 void
15364 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15365                                          const gchar  *name)
15366 {
15367   ClutterActorPrivate *priv;
15368   ClutterActorMeta *meta;
15369
15370   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15371   g_return_if_fail (name != NULL);
15372
15373   priv = self->priv;
15374
15375   if (priv->constraints == NULL)
15376     return;
15377
15378   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15379   if (meta == NULL)
15380     return;
15381
15382   _clutter_meta_group_remove_meta (priv->constraints, meta);
15383   clutter_actor_queue_relayout (self);
15384 }
15385
15386 /**
15387  * clutter_actor_get_constraints:
15388  * @self: a #ClutterActor
15389  *
15390  * Retrieves the list of constraints applied to @self
15391  *
15392  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15393  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15394  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15395  *   allocated by the returned #GList
15396  *
15397  * Since: 1.4
15398  */
15399 GList *
15400 clutter_actor_get_constraints (ClutterActor *self)
15401 {
15402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15403
15404   if (self->priv->constraints == NULL)
15405     return NULL;
15406
15407   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15408 }
15409
15410 /**
15411  * clutter_actor_get_constraint:
15412  * @self: a #ClutterActor
15413  * @name: the name of the constraint to retrieve
15414  *
15415  * Retrieves the #ClutterConstraint with the given name in the list
15416  * of constraints applied to @self
15417  *
15418  * Return value: (transfer none): a #ClutterConstraint for the given
15419  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15420  *   actor and it should not be unreferenced directly
15421  *
15422  * Since: 1.4
15423  */
15424 ClutterConstraint *
15425 clutter_actor_get_constraint (ClutterActor *self,
15426                               const gchar  *name)
15427 {
15428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15429   g_return_val_if_fail (name != NULL, NULL);
15430
15431   if (self->priv->constraints == NULL)
15432     return NULL;
15433
15434   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15435 }
15436
15437 /**
15438  * clutter_actor_clear_constraints:
15439  * @self: a #ClutterActor
15440  *
15441  * Clears the list of constraints applied to @self
15442  *
15443  * Since: 1.4
15444  */
15445 void
15446 clutter_actor_clear_constraints (ClutterActor *self)
15447 {
15448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15449
15450   if (self->priv->constraints == NULL)
15451     return;
15452
15453   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15454
15455   clutter_actor_queue_relayout (self);
15456 }
15457
15458 /**
15459  * clutter_actor_set_clip_to_allocation:
15460  * @self: a #ClutterActor
15461  * @clip_set: %TRUE to apply a clip tracking the allocation
15462  *
15463  * Sets whether @self should be clipped to the same size as its
15464  * allocation
15465  *
15466  * Since: 1.4
15467  */
15468 void
15469 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15470                                       gboolean      clip_set)
15471 {
15472   ClutterActorPrivate *priv;
15473
15474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15475
15476   clip_set = !!clip_set;
15477
15478   priv = self->priv;
15479
15480   if (priv->clip_to_allocation != clip_set)
15481     {
15482       priv->clip_to_allocation = clip_set;
15483
15484       clutter_actor_queue_redraw (self);
15485
15486       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15487     }
15488 }
15489
15490 /**
15491  * clutter_actor_get_clip_to_allocation:
15492  * @self: a #ClutterActor
15493  *
15494  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15495  *
15496  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15497  *
15498  * Since: 1.4
15499  */
15500 gboolean
15501 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15502 {
15503   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15504
15505   return self->priv->clip_to_allocation;
15506 }
15507
15508 /**
15509  * clutter_actor_add_effect:
15510  * @self: a #ClutterActor
15511  * @effect: a #ClutterEffect
15512  *
15513  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15514  *
15515  * The #ClutterActor will hold a reference on the @effect until either
15516  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15517  * called.
15518  *
15519  * Since: 1.4
15520  */
15521 void
15522 clutter_actor_add_effect (ClutterActor  *self,
15523                           ClutterEffect *effect)
15524 {
15525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15526   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15527
15528   _clutter_actor_add_effect_internal (self, effect);
15529
15530   clutter_actor_queue_redraw (self);
15531
15532   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15533 }
15534
15535 /**
15536  * clutter_actor_add_effect_with_name:
15537  * @self: a #ClutterActor
15538  * @name: the name to set on the effect
15539  * @effect: a #ClutterEffect
15540  *
15541  * A convenience function for setting the name of a #ClutterEffect
15542  * while adding it to the list of effectss applied to @self
15543  *
15544  * This function is the logical equivalent of:
15545  *
15546  * |[
15547  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15548  *   clutter_actor_add_effect (self, effect);
15549  * ]|
15550  *
15551  * Since: 1.4
15552  */
15553 void
15554 clutter_actor_add_effect_with_name (ClutterActor  *self,
15555                                     const gchar   *name,
15556                                     ClutterEffect *effect)
15557 {
15558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15559   g_return_if_fail (name != NULL);
15560   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15561
15562   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15563   clutter_actor_add_effect (self, effect);
15564 }
15565
15566 /**
15567  * clutter_actor_remove_effect:
15568  * @self: a #ClutterActor
15569  * @effect: a #ClutterEffect
15570  *
15571  * Removes @effect from the list of effects applied to @self
15572  *
15573  * The reference held by @self on the #ClutterEffect will be released
15574  *
15575  * Since: 1.4
15576  */
15577 void
15578 clutter_actor_remove_effect (ClutterActor  *self,
15579                              ClutterEffect *effect)
15580 {
15581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15582   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15583
15584   _clutter_actor_remove_effect_internal (self, effect);
15585
15586   clutter_actor_queue_redraw (self);
15587
15588   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15589 }
15590
15591 /**
15592  * clutter_actor_remove_effect_by_name:
15593  * @self: a #ClutterActor
15594  * @name: the name of the effect to remove
15595  *
15596  * Removes the #ClutterEffect with the given name from the list
15597  * of effects applied to @self
15598  *
15599  * Since: 1.4
15600  */
15601 void
15602 clutter_actor_remove_effect_by_name (ClutterActor *self,
15603                                      const gchar  *name)
15604 {
15605   ClutterActorPrivate *priv;
15606   ClutterActorMeta *meta;
15607
15608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15609   g_return_if_fail (name != NULL);
15610
15611   priv = self->priv;
15612
15613   if (priv->effects == NULL)
15614     return;
15615
15616   meta = _clutter_meta_group_get_meta (priv->effects, name);
15617   if (meta == NULL)
15618     return;
15619
15620   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15621 }
15622
15623 /**
15624  * clutter_actor_get_effects:
15625  * @self: a #ClutterActor
15626  *
15627  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15628  *
15629  * Return value: (transfer container) (element-type Clutter.Effect): a list
15630  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15631  *   list are owned by Clutter and they should not be freed. You should
15632  *   free the returned list using g_list_free() when done
15633  *
15634  * Since: 1.4
15635  */
15636 GList *
15637 clutter_actor_get_effects (ClutterActor *self)
15638 {
15639   ClutterActorPrivate *priv;
15640
15641   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15642
15643   priv = self->priv;
15644
15645   if (priv->effects == NULL)
15646     return NULL;
15647
15648   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15649 }
15650
15651 /**
15652  * clutter_actor_get_effect:
15653  * @self: a #ClutterActor
15654  * @name: the name of the effect to retrieve
15655  *
15656  * Retrieves the #ClutterEffect with the given name in the list
15657  * of effects applied to @self
15658  *
15659  * Return value: (transfer none): a #ClutterEffect for the given
15660  *   name, or %NULL. The returned #ClutterEffect is owned by the
15661  *   actor and it should not be unreferenced directly
15662  *
15663  * Since: 1.4
15664  */
15665 ClutterEffect *
15666 clutter_actor_get_effect (ClutterActor *self,
15667                           const gchar  *name)
15668 {
15669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15670   g_return_val_if_fail (name != NULL, NULL);
15671
15672   if (self->priv->effects == NULL)
15673     return NULL;
15674
15675   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15676 }
15677
15678 /**
15679  * clutter_actor_clear_effects:
15680  * @self: a #ClutterActor
15681  *
15682  * Clears the list of effects applied to @self
15683  *
15684  * Since: 1.4
15685  */
15686 void
15687 clutter_actor_clear_effects (ClutterActor *self)
15688 {
15689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15690
15691   if (self->priv->effects == NULL)
15692     return;
15693
15694   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15695
15696   clutter_actor_queue_redraw (self);
15697 }
15698
15699 /**
15700  * clutter_actor_has_key_focus:
15701  * @self: a #ClutterActor
15702  *
15703  * Checks whether @self is the #ClutterActor that has key focus
15704  *
15705  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15706  *
15707  * Since: 1.4
15708  */
15709 gboolean
15710 clutter_actor_has_key_focus (ClutterActor *self)
15711 {
15712   ClutterActor *stage;
15713
15714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15715
15716   stage = _clutter_actor_get_stage_internal (self);
15717   if (stage == NULL)
15718     return FALSE;
15719
15720   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15721 }
15722
15723 static gboolean
15724 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15725                                       ClutterPaintVolume *pv)
15726 {
15727   ClutterActorPrivate *priv = self->priv;
15728
15729   /* Actors are only expected to report a valid paint volume
15730    * while they have a valid allocation. */
15731   if (G_UNLIKELY (priv->needs_allocation))
15732     {
15733       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15734                     "Actor needs allocation",
15735                     _clutter_actor_get_debug_name (self));
15736       return FALSE;
15737     }
15738
15739   /* Check if there are any handlers connected to the paint
15740    * signal. If there are then all bets are off for what the paint
15741    * volume for this actor might possibly be!
15742    *
15743    * XXX: It's expected that this is going to end up being quite a
15744    * costly check to have to do here, but we haven't come up with
15745    * another solution that can reliably catch paint signal handlers at
15746    * the right time to either avoid artefacts due to invalid stage
15747    * clipping or due to incorrect culling.
15748    *
15749    * Previously we checked in clutter_actor_paint(), but at that time
15750    * we may already be using a stage clip that could be derived from
15751    * an invalid paint-volume. We used to try and handle that by
15752    * queuing a follow up, unclipped, redraw but still the previous
15753    * checking wasn't enough to catch invalid volumes involved in
15754    * culling (considering that containers may derive their volume from
15755    * children that haven't yet been painted)
15756    *
15757    * Longer term, improved solutions could be:
15758    * - Disallow painting in the paint signal, only allow using it
15759    *   for tracking when paints happen. We can add another API that
15760    *   allows monkey patching the paint of arbitrary actors but in a
15761    *   more controlled way and that also supports modifying the
15762    *   paint-volume.
15763    * - If we could be notified somehow when signal handlers are
15764    *   connected we wouldn't have to poll for handlers like this.
15765    */
15766   if (g_signal_has_handler_pending (self,
15767                                     actor_signals[PAINT],
15768                                     0,
15769                                     TRUE))
15770     {
15771       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15772                     "Actor has \"paint\" signal handlers",
15773                     _clutter_actor_get_debug_name (self));
15774       return FALSE;
15775     }
15776
15777   _clutter_paint_volume_init_static (pv, self);
15778
15779   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15780     {
15781       clutter_paint_volume_free (pv);
15782       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15783                     "Actor failed to report a volume",
15784                     _clutter_actor_get_debug_name (self));
15785       return FALSE;
15786     }
15787
15788   /* since effects can modify the paint volume, we allow them to actually
15789    * do this by making get_paint_volume() "context sensitive"
15790    */
15791   if (priv->effects != NULL)
15792     {
15793       if (priv->current_effect != NULL)
15794         {
15795           const GList *effects, *l;
15796
15797           /* if we are being called from within the paint sequence of
15798            * an actor, get the paint volume up to the current effect
15799            */
15800           effects = _clutter_meta_group_peek_metas (priv->effects);
15801           for (l = effects;
15802                l != NULL || (l != NULL && l->data != priv->current_effect);
15803                l = l->next)
15804             {
15805               if (!_clutter_effect_get_paint_volume (l->data, pv))
15806                 {
15807                   clutter_paint_volume_free (pv);
15808                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15809                                 "Effect (%s) failed to report a volume",
15810                                 _clutter_actor_get_debug_name (self),
15811                                 _clutter_actor_meta_get_debug_name (l->data));
15812                   return FALSE;
15813                 }
15814             }
15815         }
15816       else
15817         {
15818           const GList *effects, *l;
15819
15820           /* otherwise, get the cumulative volume */
15821           effects = _clutter_meta_group_peek_metas (priv->effects);
15822           for (l = effects; l != NULL; l = l->next)
15823             if (!_clutter_effect_get_paint_volume (l->data, pv))
15824               {
15825                 clutter_paint_volume_free (pv);
15826                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15827                               "Effect (%s) failed to report a volume",
15828                               _clutter_actor_get_debug_name (self),
15829                               _clutter_actor_meta_get_debug_name (l->data));
15830                 return FALSE;
15831               }
15832         }
15833     }
15834
15835   return TRUE;
15836 }
15837
15838 /* The public clutter_actor_get_paint_volume API returns a const
15839  * pointer since we return a pointer directly to the cached
15840  * PaintVolume associated with the actor and don't want the user to
15841  * inadvertently modify it, but for internal uses we sometimes need
15842  * access to the same PaintVolume but need to apply some book-keeping
15843  * modifications to it so we don't want a const pointer.
15844  */
15845 static ClutterPaintVolume *
15846 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15847 {
15848   ClutterActorPrivate *priv;
15849
15850   priv = self->priv;
15851
15852   if (priv->paint_volume_valid)
15853     clutter_paint_volume_free (&priv->paint_volume);
15854
15855   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15856     {
15857       priv->paint_volume_valid = TRUE;
15858       return &priv->paint_volume;
15859     }
15860   else
15861     {
15862       priv->paint_volume_valid = FALSE;
15863       return NULL;
15864     }
15865 }
15866
15867 /**
15868  * clutter_actor_get_paint_volume:
15869  * @self: a #ClutterActor
15870  *
15871  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15872  * when a paint volume can't be determined.
15873  *
15874  * The paint volume is defined as the 3D space occupied by an actor
15875  * when being painted.
15876  *
15877  * This function will call the <function>get_paint_volume()</function>
15878  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15879  * should not usually care about overriding the default implementation,
15880  * unless they are, for instance: painting outside their allocation, or
15881  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15882  * 3D depth).
15883  *
15884  * <note>2D actors overriding <function>get_paint_volume()</function>
15885  * ensure their volume has a depth of 0. (This will be true so long as
15886  * you don't call clutter_paint_volume_set_depth().)</note>
15887  *
15888  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15889  *   or %NULL if no volume could be determined. The returned pointer
15890  *   is not guaranteed to be valid across multiple frames; if you want
15891  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15892  *
15893  * Since: 1.6
15894  */
15895 const ClutterPaintVolume *
15896 clutter_actor_get_paint_volume (ClutterActor *self)
15897 {
15898   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15899
15900   return _clutter_actor_get_paint_volume_mutable (self);
15901 }
15902
15903 /**
15904  * clutter_actor_get_transformed_paint_volume:
15905  * @self: a #ClutterActor
15906  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15907  *    (or %NULL for the stage)
15908  *
15909  * Retrieves the 3D paint volume of an actor like
15910  * clutter_actor_get_paint_volume() does (Please refer to the
15911  * documentation of clutter_actor_get_paint_volume() for more
15912  * details.) and it additionally transforms the paint volume into the
15913  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15914  * is passed for @relative_to_ancestor)
15915  *
15916  * This can be used by containers that base their paint volume on
15917  * the volume of their children. Such containers can query the
15918  * transformed paint volume of all of its children and union them
15919  * together using clutter_paint_volume_union().
15920  *
15921  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15922  *   or %NULL if no volume could be determined. The returned pointer is
15923  *   not guaranteed to be valid across multiple frames; if you wish to
15924  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15925  *
15926  * Since: 1.6
15927  */
15928 const ClutterPaintVolume *
15929 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15930                                             ClutterActor *relative_to_ancestor)
15931 {
15932   const ClutterPaintVolume *volume;
15933   ClutterActor *stage;
15934   ClutterPaintVolume *transformed_volume;
15935
15936   stage = _clutter_actor_get_stage_internal (self);
15937   if (G_UNLIKELY (stage == NULL))
15938     return NULL;
15939
15940   if (relative_to_ancestor == NULL)
15941     relative_to_ancestor = stage;
15942
15943   volume = clutter_actor_get_paint_volume (self);
15944   if (volume == NULL)
15945     return NULL;
15946
15947   transformed_volume =
15948     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15949
15950   _clutter_paint_volume_copy_static (volume, transformed_volume);
15951
15952   _clutter_paint_volume_transform_relative (transformed_volume,
15953                                             relative_to_ancestor);
15954
15955   return transformed_volume;
15956 }
15957
15958 /**
15959  * clutter_actor_get_paint_box:
15960  * @self: a #ClutterActor
15961  * @box: (out): return location for a #ClutterActorBox
15962  *
15963  * Retrieves the paint volume of the passed #ClutterActor, and
15964  * transforms it into a 2D bounding box in stage coordinates.
15965  *
15966  * This function is useful to determine the on screen area occupied by
15967  * the actor. The box is only an approximation and may often be
15968  * considerably larger due to the optimizations used to calculate the
15969  * box. The box is never smaller though, so it can reliably be used
15970  * for culling.
15971  *
15972  * There are times when a 2D paint box can't be determined, e.g.
15973  * because the actor isn't yet parented under a stage or because
15974  * the actor is unable to determine a paint volume.
15975  *
15976  * Return value: %TRUE if a 2D paint box could be determined, else
15977  * %FALSE.
15978  *
15979  * Since: 1.6
15980  */
15981 gboolean
15982 clutter_actor_get_paint_box (ClutterActor    *self,
15983                              ClutterActorBox *box)
15984 {
15985   ClutterActor *stage;
15986   ClutterPaintVolume *pv;
15987
15988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15989   g_return_val_if_fail (box != NULL, FALSE);
15990
15991   stage = _clutter_actor_get_stage_internal (self);
15992   if (G_UNLIKELY (!stage))
15993     return FALSE;
15994
15995   pv = _clutter_actor_get_paint_volume_mutable (self);
15996   if (G_UNLIKELY (!pv))
15997     return FALSE;
15998
15999   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
16000
16001   return TRUE;
16002 }
16003
16004 /**
16005  * clutter_actor_has_overlaps:
16006  * @self: A #ClutterActor
16007  *
16008  * Asks the actor's implementation whether it may contain overlapping
16009  * primitives.
16010  *
16011  * For example; Clutter may use this to determine whether the painting
16012  * should be redirected to an offscreen buffer to correctly implement
16013  * the opacity property.
16014  *
16015  * Custom actors can override the default response by implementing the
16016  * #ClutterActor <function>has_overlaps</function> virtual function. See
16017  * clutter_actor_set_offscreen_redirect() for more information.
16018  *
16019  * Return value: %TRUE if the actor may have overlapping primitives, and
16020  *   %FALSE otherwise
16021  *
16022  * Since: 1.8
16023  */
16024 gboolean
16025 clutter_actor_has_overlaps (ClutterActor *self)
16026 {
16027   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
16028
16029   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
16030 }
16031
16032 /**
16033  * clutter_actor_has_effects:
16034  * @self: A #ClutterActor
16035  *
16036  * Returns whether the actor has any effects applied.
16037  *
16038  * Return value: %TRUE if the actor has any effects,
16039  *   %FALSE otherwise
16040  *
16041  * Since: 1.10
16042  */
16043 gboolean
16044 clutter_actor_has_effects (ClutterActor *self)
16045 {
16046   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16047
16048   if (self->priv->effects == NULL)
16049     return FALSE;
16050
16051   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16052 }
16053
16054 /**
16055  * clutter_actor_has_constraints:
16056  * @self: A #ClutterActor
16057  *
16058  * Returns whether the actor has any constraints applied.
16059  *
16060  * Return value: %TRUE if the actor has any constraints,
16061  *   %FALSE otherwise
16062  *
16063  * Since: 1.10
16064  */
16065 gboolean
16066 clutter_actor_has_constraints (ClutterActor *self)
16067 {
16068   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16069
16070   return self->priv->constraints != NULL;
16071 }
16072
16073 /**
16074  * clutter_actor_has_actions:
16075  * @self: A #ClutterActor
16076  *
16077  * Returns whether the actor has any actions applied.
16078  *
16079  * Return value: %TRUE if the actor has any actions,
16080  *   %FALSE otherwise
16081  *
16082  * Since: 1.10
16083  */
16084 gboolean
16085 clutter_actor_has_actions (ClutterActor *self)
16086 {
16087   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16088
16089   return self->priv->actions != NULL;
16090 }
16091
16092 /**
16093  * clutter_actor_get_n_children:
16094  * @self: a #ClutterActor
16095  *
16096  * Retrieves the number of children of @self.
16097  *
16098  * Return value: the number of children of an actor
16099  *
16100  * Since: 1.10
16101  */
16102 gint
16103 clutter_actor_get_n_children (ClutterActor *self)
16104 {
16105   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16106
16107   return self->priv->n_children;
16108 }
16109
16110 /**
16111  * clutter_actor_get_child_at_index:
16112  * @self: a #ClutterActor
16113  * @index_: the position in the list of children
16114  *
16115  * Retrieves the actor at the given @index_ inside the list of
16116  * children of @self.
16117  *
16118  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16119  *
16120  * Since: 1.10
16121  */
16122 ClutterActor *
16123 clutter_actor_get_child_at_index (ClutterActor *self,
16124                                   gint          index_)
16125 {
16126   ClutterActor *iter;
16127   int i;
16128
16129   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16130   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16131
16132   for (iter = self->priv->first_child, i = 0;
16133        iter != NULL && i < index_;
16134        iter = iter->priv->next_sibling, i += 1)
16135     ;
16136
16137   return iter;
16138 }
16139
16140 /*< private >
16141  * _clutter_actor_foreach_child:
16142  * @actor: The actor whos children you want to iterate
16143  * @callback: The function to call for each child
16144  * @user_data: Private data to pass to @callback
16145  *
16146  * Calls a given @callback once for each child of the specified @actor and
16147  * passing the @user_data pointer each time.
16148  *
16149  * Return value: returns %TRUE if all children were iterated, else
16150  *    %FALSE if a callback broke out of iteration early.
16151  */
16152 gboolean
16153 _clutter_actor_foreach_child (ClutterActor           *self,
16154                               ClutterForeachCallback  callback,
16155                               gpointer                user_data)
16156 {
16157   ClutterActor *iter;
16158   gboolean cont;
16159
16160   if (self->priv->first_child == NULL)
16161     return TRUE;
16162
16163   cont = TRUE;
16164   iter = self->priv->first_child;
16165
16166   /* we use this form so that it's safe to change the children
16167    * list while iterating it
16168    */
16169   while (cont && iter != NULL)
16170     {
16171       ClutterActor *next = iter->priv->next_sibling;
16172
16173       cont = callback (iter, user_data);
16174
16175       iter = next;
16176     }
16177
16178   return cont;
16179 }
16180
16181 #if 0
16182 /* For debugging purposes this gives us a simple way to print out
16183  * the scenegraph e.g in gdb using:
16184  * [|
16185  *   _clutter_actor_traverse (stage,
16186  *                            0,
16187  *                            clutter_debug_print_actor_cb,
16188  *                            NULL,
16189  *                            NULL);
16190  * |]
16191  */
16192 static ClutterActorTraverseVisitFlags
16193 clutter_debug_print_actor_cb (ClutterActor *actor,
16194                               int depth,
16195                               void *user_data)
16196 {
16197   g_print ("%*s%s:%p\n",
16198            depth * 2, "",
16199            _clutter_actor_get_debug_name (actor),
16200            actor);
16201
16202   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16203 }
16204 #endif
16205
16206 static void
16207 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16208                                  ClutterTraverseCallback callback,
16209                                  gpointer                user_data)
16210 {
16211   GQueue *queue = g_queue_new ();
16212   ClutterActor dummy;
16213   int current_depth = 0;
16214
16215   g_queue_push_tail (queue, actor);
16216   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16217
16218   while ((actor = g_queue_pop_head (queue)))
16219     {
16220       ClutterActorTraverseVisitFlags flags;
16221
16222       if (actor == &dummy)
16223         {
16224           current_depth++;
16225           g_queue_push_tail (queue, &dummy);
16226           continue;
16227         }
16228
16229       flags = callback (actor, current_depth, user_data);
16230       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16231         break;
16232       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16233         {
16234           ClutterActor *iter;
16235
16236           for (iter = actor->priv->first_child;
16237                iter != NULL;
16238                iter = iter->priv->next_sibling)
16239             {
16240               g_queue_push_tail (queue, iter);
16241             }
16242         }
16243     }
16244
16245   g_queue_free (queue);
16246 }
16247
16248 static ClutterActorTraverseVisitFlags
16249 _clutter_actor_traverse_depth (ClutterActor           *actor,
16250                                ClutterTraverseCallback before_children_callback,
16251                                ClutterTraverseCallback after_children_callback,
16252                                int                     current_depth,
16253                                gpointer                user_data)
16254 {
16255   ClutterActorTraverseVisitFlags flags;
16256
16257   flags = before_children_callback (actor, current_depth, user_data);
16258   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16259     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16260
16261   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16262     {
16263       ClutterActor *iter;
16264
16265       for (iter = actor->priv->first_child;
16266            iter != NULL;
16267            iter = iter->priv->next_sibling)
16268         {
16269           flags = _clutter_actor_traverse_depth (iter,
16270                                                  before_children_callback,
16271                                                  after_children_callback,
16272                                                  current_depth + 1,
16273                                                  user_data);
16274
16275           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16276             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16277         }
16278     }
16279
16280   if (after_children_callback)
16281     return after_children_callback (actor, current_depth, user_data);
16282   else
16283     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16284 }
16285
16286 /* _clutter_actor_traverse:
16287  * @actor: The actor to start traversing the graph from
16288  * @flags: These flags may affect how the traversal is done
16289  * @before_children_callback: A function to call before visiting the
16290  *   children of the current actor.
16291  * @after_children_callback: A function to call after visiting the
16292  *   children of the current actor. (Ignored if
16293  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16294  * @user_data: The private data to pass to the callbacks
16295  *
16296  * Traverses the scenegraph starting at the specified @actor and
16297  * descending through all its children and its children's children.
16298  * For each actor traversed @before_children_callback and
16299  * @after_children_callback are called with the specified
16300  * @user_data, before and after visiting that actor's children.
16301  *
16302  * The callbacks can return flags that affect the ongoing traversal
16303  * such as by skipping over an actors children or bailing out of
16304  * any further traversing.
16305  */
16306 void
16307 _clutter_actor_traverse (ClutterActor              *actor,
16308                          ClutterActorTraverseFlags  flags,
16309                          ClutterTraverseCallback    before_children_callback,
16310                          ClutterTraverseCallback    after_children_callback,
16311                          gpointer                   user_data)
16312 {
16313   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16314     _clutter_actor_traverse_breadth (actor,
16315                                      before_children_callback,
16316                                      user_data);
16317   else /* DEPTH_FIRST */
16318     _clutter_actor_traverse_depth (actor,
16319                                    before_children_callback,
16320                                    after_children_callback,
16321                                    0, /* start depth */
16322                                    user_data);
16323 }
16324
16325 static void
16326 on_layout_manager_changed (ClutterLayoutManager *manager,
16327                            ClutterActor         *self)
16328 {
16329   clutter_actor_queue_relayout (self);
16330 }
16331
16332 /**
16333  * clutter_actor_set_layout_manager:
16334  * @self: a #ClutterActor
16335  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16336  *
16337  * Sets the #ClutterLayoutManager delegate object that will be used to
16338  * lay out the children of @self.
16339  *
16340  * The #ClutterActor will take a reference on the passed @manager which
16341  * will be released either when the layout manager is removed, or when
16342  * the actor is destroyed.
16343  *
16344  * Since: 1.10
16345  */
16346 void
16347 clutter_actor_set_layout_manager (ClutterActor         *self,
16348                                   ClutterLayoutManager *manager)
16349 {
16350   ClutterActorPrivate *priv;
16351
16352   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16353   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16354
16355   priv = self->priv;
16356
16357   if (priv->layout_manager != NULL)
16358     {
16359       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16360                                             G_CALLBACK (on_layout_manager_changed),
16361                                             self);
16362       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16363       g_clear_object (&priv->layout_manager);
16364     }
16365
16366   priv->layout_manager = manager;
16367
16368   if (priv->layout_manager != NULL)
16369     {
16370       g_object_ref_sink (priv->layout_manager);
16371       clutter_layout_manager_set_container (priv->layout_manager,
16372                                             CLUTTER_CONTAINER (self));
16373       g_signal_connect (priv->layout_manager, "layout-changed",
16374                         G_CALLBACK (on_layout_manager_changed),
16375                         self);
16376     }
16377
16378   clutter_actor_queue_relayout (self);
16379
16380   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16381 }
16382
16383 /**
16384  * clutter_actor_get_layout_manager:
16385  * @self: a #ClutterActor
16386  *
16387  * Retrieves the #ClutterLayoutManager used by @self.
16388  *
16389  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16390  *   or %NULL
16391  *
16392  * Since: 1.10
16393  */
16394 ClutterLayoutManager *
16395 clutter_actor_get_layout_manager (ClutterActor *self)
16396 {
16397   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16398
16399   return self->priv->layout_manager;
16400 }
16401
16402 static const ClutterLayoutInfo default_layout_info = {
16403   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16404   { 0, 0, 0, 0 },               /* margin */
16405   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16406   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16407   FALSE, FALSE,                 /* expand */
16408   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16409   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16410 };
16411
16412 static void
16413 layout_info_free (gpointer data)
16414 {
16415   if (G_LIKELY (data != NULL))
16416     g_slice_free (ClutterLayoutInfo, data);
16417 }
16418
16419 /*< private >
16420  * _clutter_actor_peek_layout_info:
16421  * @self: a #ClutterActor
16422  *
16423  * Retrieves a pointer to the ClutterLayoutInfo structure.
16424  *
16425  * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16426  *
16427  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16428  */
16429 ClutterLayoutInfo *
16430 _clutter_actor_peek_layout_info (ClutterActor *self)
16431 {
16432   return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16433 }
16434
16435 /*< private >
16436  * _clutter_actor_get_layout_info:
16437  * @self: a #ClutterActor
16438  *
16439  * Retrieves a pointer to the ClutterLayoutInfo structure.
16440  *
16441  * If the actor does not have a ClutterLayoutInfo associated to it, one
16442  * will be created and initialized to the default values.
16443  *
16444  * This function should be used for setters.
16445  *
16446  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16447  * instead.
16448  *
16449  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16450  */
16451 ClutterLayoutInfo *
16452 _clutter_actor_get_layout_info (ClutterActor *self)
16453 {
16454   ClutterLayoutInfo *retval;
16455
16456   retval = _clutter_actor_peek_layout_info (self);
16457   if (retval == NULL)
16458     {
16459       retval = g_slice_new (ClutterLayoutInfo);
16460
16461       *retval = default_layout_info;
16462
16463       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16464                                retval,
16465                                layout_info_free);
16466     }
16467
16468   return retval;
16469 }
16470
16471 /*< private >
16472  * _clutter_actor_get_layout_info_or_defaults:
16473  * @self: a #ClutterActor
16474  *
16475  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16476  *
16477  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16478  * then the default structure will be returned.
16479  *
16480  * This function should only be used for getters.
16481  *
16482  * Return value: a const pointer to the ClutterLayoutInfo structure
16483  */
16484 const ClutterLayoutInfo *
16485 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16486 {
16487   const ClutterLayoutInfo *info;
16488
16489   info = _clutter_actor_peek_layout_info (self);
16490   if (info == NULL)
16491     return &default_layout_info;
16492
16493   return info;
16494 }
16495
16496 /**
16497  * clutter_actor_set_x_align:
16498  * @self: a #ClutterActor
16499  * @x_align: the horizontal alignment policy
16500  *
16501  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16502  * actor received extra horizontal space.
16503  *
16504  * See also the #ClutterActor:x-align property.
16505  *
16506  * Since: 1.10
16507  */
16508 void
16509 clutter_actor_set_x_align (ClutterActor      *self,
16510                            ClutterActorAlign  x_align)
16511 {
16512   ClutterLayoutInfo *info;
16513
16514   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16515
16516   info = _clutter_actor_get_layout_info (self);
16517
16518   if (info->x_align != x_align)
16519     {
16520       info->x_align = x_align;
16521
16522       clutter_actor_queue_relayout (self);
16523
16524       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16525     }
16526 }
16527
16528 /**
16529  * clutter_actor_get_x_align:
16530  * @self: a #ClutterActor
16531  *
16532  * Retrieves the horizontal alignment policy set using
16533  * clutter_actor_set_x_align().
16534  *
16535  * Return value: the horizontal alignment policy.
16536  *
16537  * Since: 1.10
16538  */
16539 ClutterActorAlign
16540 clutter_actor_get_x_align (ClutterActor *self)
16541 {
16542   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16543
16544   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16545 }
16546
16547 /**
16548  * clutter_actor_set_y_align:
16549  * @self: a #ClutterActor
16550  * @y_align: the vertical alignment policy
16551  *
16552  * Sets the vertical alignment policy of a #ClutterActor, in case the
16553  * actor received extra vertical space.
16554  *
16555  * See also the #ClutterActor:y-align property.
16556  *
16557  * Since: 1.10
16558  */
16559 void
16560 clutter_actor_set_y_align (ClutterActor      *self,
16561                            ClutterActorAlign  y_align)
16562 {
16563   ClutterLayoutInfo *info;
16564
16565   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16566
16567   info = _clutter_actor_get_layout_info (self);
16568
16569   if (info->y_align != y_align)
16570     {
16571       info->y_align = y_align;
16572
16573       clutter_actor_queue_relayout (self);
16574
16575       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16576     }
16577 }
16578
16579 /**
16580  * clutter_actor_get_y_align:
16581  * @self: a #ClutterActor
16582  *
16583  * Retrieves the vertical alignment policy set using
16584  * clutter_actor_set_y_align().
16585  *
16586  * Return value: the vertical alignment policy.
16587  *
16588  * Since: 1.10
16589  */
16590 ClutterActorAlign
16591 clutter_actor_get_y_align (ClutterActor *self)
16592 {
16593   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16594
16595   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16596 }
16597
16598 /**
16599  * clutter_actor_set_margin:
16600  * @self: a #ClutterActor
16601  * @margin: a #ClutterMargin
16602  *
16603  * Sets all the components of the margin of a #ClutterActor.
16604  *
16605  * Since: 1.10
16606  */
16607 void
16608 clutter_actor_set_margin (ClutterActor        *self,
16609                           const ClutterMargin *margin)
16610 {
16611   ClutterLayoutInfo *info;
16612   gboolean changed;
16613   GObject *obj;
16614
16615   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16616   g_return_if_fail (margin != NULL);
16617
16618   obj = G_OBJECT (self);
16619   changed = FALSE;
16620
16621   g_object_freeze_notify (obj);
16622
16623   info = _clutter_actor_get_layout_info (self);
16624
16625   if (info->margin.top != margin->top)
16626     {
16627       info->margin.top = margin->top;
16628       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16629       changed = TRUE;
16630     }
16631
16632   if (info->margin.right != margin->right)
16633     {
16634       info->margin.right = margin->right;
16635       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16636       changed = TRUE;
16637     }
16638
16639   if (info->margin.bottom != margin->bottom)
16640     {
16641       info->margin.bottom = margin->bottom;
16642       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16643       changed = TRUE;
16644     }
16645
16646   if (info->margin.left != margin->left)
16647     {
16648       info->margin.left = margin->left;
16649       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16650       changed = TRUE;
16651     }
16652
16653   if (changed)
16654     clutter_actor_queue_relayout (self);
16655
16656   g_object_thaw_notify (obj);
16657 }
16658
16659 /**
16660  * clutter_actor_get_margin:
16661  * @self: a #ClutterActor
16662  * @margin: (out caller-allocates): return location for a #ClutterMargin
16663  *
16664  * Retrieves all the components of the margin of a #ClutterActor.
16665  *
16666  * Since: 1.10
16667  */
16668 void
16669 clutter_actor_get_margin (ClutterActor  *self,
16670                           ClutterMargin *margin)
16671 {
16672   const ClutterLayoutInfo *info;
16673
16674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16675   g_return_if_fail (margin != NULL);
16676
16677   info = _clutter_actor_get_layout_info_or_defaults (self);
16678
16679   *margin = info->margin;
16680 }
16681
16682 /**
16683  * clutter_actor_set_margin_top:
16684  * @self: a #ClutterActor
16685  * @margin: the top margin
16686  *
16687  * Sets the margin from the top of a #ClutterActor.
16688  *
16689  * Since: 1.10
16690  */
16691 void
16692 clutter_actor_set_margin_top (ClutterActor *self,
16693                               gfloat        margin)
16694 {
16695   ClutterLayoutInfo *info;
16696
16697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16698   g_return_if_fail (margin >= 0.f);
16699
16700   info = _clutter_actor_get_layout_info (self);
16701
16702   if (info->margin.top == margin)
16703     return;
16704
16705   info->margin.top = margin;
16706
16707   clutter_actor_queue_relayout (self);
16708
16709   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16710 }
16711
16712 /**
16713  * clutter_actor_get_margin_top:
16714  * @self: a #ClutterActor
16715  *
16716  * Retrieves the top margin of a #ClutterActor.
16717  *
16718  * Return value: the top margin
16719  *
16720  * Since: 1.10
16721  */
16722 gfloat
16723 clutter_actor_get_margin_top (ClutterActor *self)
16724 {
16725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16726
16727   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16728 }
16729
16730 /**
16731  * clutter_actor_set_margin_bottom:
16732  * @self: a #ClutterActor
16733  * @margin: the bottom margin
16734  *
16735  * Sets the margin from the bottom of a #ClutterActor.
16736  *
16737  * Since: 1.10
16738  */
16739 void
16740 clutter_actor_set_margin_bottom (ClutterActor *self,
16741                                  gfloat        margin)
16742 {
16743   ClutterLayoutInfo *info;
16744
16745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16746   g_return_if_fail (margin >= 0.f);
16747
16748   info = _clutter_actor_get_layout_info (self);
16749
16750   if (info->margin.bottom == margin)
16751     return;
16752
16753   info->margin.bottom = margin;
16754
16755   clutter_actor_queue_relayout (self);
16756
16757   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16758 }
16759
16760 /**
16761  * clutter_actor_get_margin_bottom:
16762  * @self: a #ClutterActor
16763  *
16764  * Retrieves the bottom margin of a #ClutterActor.
16765  *
16766  * Return value: the bottom margin
16767  *
16768  * Since: 1.10
16769  */
16770 gfloat
16771 clutter_actor_get_margin_bottom (ClutterActor *self)
16772 {
16773   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16774
16775   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16776 }
16777
16778 /**
16779  * clutter_actor_set_margin_left:
16780  * @self: a #ClutterActor
16781  * @margin: the left margin
16782  *
16783  * Sets the margin from the left of a #ClutterActor.
16784  *
16785  * Since: 1.10
16786  */
16787 void
16788 clutter_actor_set_margin_left (ClutterActor *self,
16789                                gfloat        margin)
16790 {
16791   ClutterLayoutInfo *info;
16792
16793   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16794   g_return_if_fail (margin >= 0.f);
16795
16796   info = _clutter_actor_get_layout_info (self);
16797
16798   if (info->margin.left == margin)
16799     return;
16800
16801   info->margin.left = margin;
16802
16803   clutter_actor_queue_relayout (self);
16804
16805   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16806 }
16807
16808 /**
16809  * clutter_actor_get_margin_left:
16810  * @self: a #ClutterActor
16811  *
16812  * Retrieves the left margin of a #ClutterActor.
16813  *
16814  * Return value: the left margin
16815  *
16816  * Since: 1.10
16817  */
16818 gfloat
16819 clutter_actor_get_margin_left (ClutterActor *self)
16820 {
16821   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16822
16823   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16824 }
16825
16826 /**
16827  * clutter_actor_set_margin_right:
16828  * @self: a #ClutterActor
16829  * @margin: the right margin
16830  *
16831  * Sets the margin from the right of a #ClutterActor.
16832  *
16833  * Since: 1.10
16834  */
16835 void
16836 clutter_actor_set_margin_right (ClutterActor *self,
16837                                 gfloat        margin)
16838 {
16839   ClutterLayoutInfo *info;
16840
16841   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16842   g_return_if_fail (margin >= 0.f);
16843
16844   info = _clutter_actor_get_layout_info (self);
16845
16846   if (info->margin.right == margin)
16847     return;
16848
16849   info->margin.right = margin;
16850
16851   clutter_actor_queue_relayout (self);
16852
16853   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16854 }
16855
16856 /**
16857  * clutter_actor_get_margin_right:
16858  * @self: a #ClutterActor
16859  *
16860  * Retrieves the right margin of a #ClutterActor.
16861  *
16862  * Return value: the right margin
16863  *
16864  * Since: 1.10
16865  */
16866 gfloat
16867 clutter_actor_get_margin_right (ClutterActor *self)
16868 {
16869   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16870
16871   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16872 }
16873
16874 static inline void
16875 clutter_actor_set_background_color_internal (ClutterActor *self,
16876                                              const ClutterColor *color)
16877 {
16878   ClutterActorPrivate *priv = self->priv;
16879   GObject *obj;
16880
16881   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16882     return;
16883
16884   obj = G_OBJECT (self);
16885
16886   priv->bg_color = *color;
16887   priv->bg_color_set = TRUE;
16888
16889   clutter_actor_queue_redraw (self);
16890
16891   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16892   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16893 }
16894
16895 /**
16896  * clutter_actor_set_background_color:
16897  * @self: a #ClutterActor
16898  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16899  *  set color
16900  *
16901  * Sets the background color of a #ClutterActor.
16902  *
16903  * The background color will be used to cover the whole allocation of the
16904  * actor. The default background color of an actor is transparent.
16905  *
16906  * To check whether an actor has a background color, you can use the
16907  * #ClutterActor:background-color-set actor property.
16908  *
16909  * The #ClutterActor:background-color property is animatable.
16910  *
16911  * Since: 1.10
16912  */
16913 void
16914 clutter_actor_set_background_color (ClutterActor       *self,
16915                                     const ClutterColor *color)
16916 {
16917   ClutterActorPrivate *priv;
16918   GObject *obj;
16919   GParamSpec *bg_color_pspec;
16920
16921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16922
16923   obj = G_OBJECT (self);
16924
16925   priv = self->priv;
16926
16927   if (color == NULL)
16928     {
16929       priv->bg_color_set = FALSE;
16930       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16931       clutter_actor_queue_redraw (self);
16932       return;
16933     }
16934
16935   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16936   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16937     {
16938       _clutter_actor_create_transition (self, bg_color_pspec,
16939                                         &priv->bg_color,
16940                                         color);
16941     }
16942   else
16943     _clutter_actor_update_transition (self, bg_color_pspec, color);
16944
16945   clutter_actor_queue_redraw (self);
16946 }
16947
16948 /**
16949  * clutter_actor_get_background_color:
16950  * @self: a #ClutterActor
16951  * @color: (out caller-allocates): return location for a #ClutterColor
16952  *
16953  * Retrieves the color set using clutter_actor_set_background_color().
16954  *
16955  * Since: 1.10
16956  */
16957 void
16958 clutter_actor_get_background_color (ClutterActor *self,
16959                                     ClutterColor *color)
16960 {
16961   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16962   g_return_if_fail (color != NULL);
16963
16964   *color = self->priv->bg_color;
16965 }
16966
16967 /**
16968  * clutter_actor_get_previous_sibling:
16969  * @self: a #ClutterActor
16970  *
16971  * Retrieves the sibling of @self that comes before it in the list
16972  * of children of @self's parent.
16973  *
16974  * The returned pointer is only valid until the scene graph changes; it
16975  * is not safe to modify the list of children of @self while iterating
16976  * it.
16977  *
16978  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16979  *
16980  * Since: 1.10
16981  */
16982 ClutterActor *
16983 clutter_actor_get_previous_sibling (ClutterActor *self)
16984 {
16985   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16986
16987   return self->priv->prev_sibling;
16988 }
16989
16990 /**
16991  * clutter_actor_get_next_sibling:
16992  * @self: a #ClutterActor
16993  *
16994  * Retrieves the sibling of @self that comes after it in the list
16995  * of children of @self's parent.
16996  *
16997  * The returned pointer is only valid until the scene graph changes; it
16998  * is not safe to modify the list of children of @self while iterating
16999  * it.
17000  *
17001  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17002  *
17003  * Since: 1.10
17004  */
17005 ClutterActor *
17006 clutter_actor_get_next_sibling (ClutterActor *self)
17007 {
17008   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17009
17010   return self->priv->next_sibling;
17011 }
17012
17013 /**
17014  * clutter_actor_get_first_child:
17015  * @self: a #ClutterActor
17016  *
17017  * Retrieves the first child of @self.
17018  *
17019  * The returned pointer is only valid until the scene graph changes; it
17020  * is not safe to modify the list of children of @self while iterating
17021  * it.
17022  *
17023  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17024  *
17025  * Since: 1.10
17026  */
17027 ClutterActor *
17028 clutter_actor_get_first_child (ClutterActor *self)
17029 {
17030   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17031
17032   return self->priv->first_child;
17033 }
17034
17035 /**
17036  * clutter_actor_get_last_child:
17037  * @self: a #ClutterActor
17038  *
17039  * Retrieves the last child of @self.
17040  *
17041  * The returned pointer is only valid until the scene graph changes; it
17042  * is not safe to modify the list of children of @self while iterating
17043  * it.
17044  *
17045  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17046  *
17047  * Since: 1.10
17048  */
17049 ClutterActor *
17050 clutter_actor_get_last_child (ClutterActor *self)
17051 {
17052   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17053
17054   return self->priv->last_child;
17055 }
17056
17057 /* easy way to have properly named fields instead of the dummy ones
17058  * we use in the public structure
17059  */
17060 typedef struct _RealActorIter
17061 {
17062   ClutterActor *root;           /* dummy1 */
17063   ClutterActor *current;        /* dummy2 */
17064   gpointer padding_1;           /* dummy3 */
17065   gint age;                     /* dummy4 */
17066   gpointer padding_2;           /* dummy5 */
17067 } RealActorIter;
17068
17069 /**
17070  * clutter_actor_iter_init:
17071  * @iter: a #ClutterActorIter
17072  * @root: a #ClutterActor
17073  *
17074  * Initializes a #ClutterActorIter, which can then be used to iterate
17075  * efficiently over a section of the scene graph, and associates it
17076  * with @root.
17077  *
17078  * Modifying the scene graph section that contains @root will invalidate
17079  * the iterator.
17080  *
17081  * |[
17082  *   ClutterActorIter iter;
17083  *   ClutterActor *child;
17084  *
17085  *   clutter_actor_iter_init (&iter, container);
17086  *   while (clutter_actor_iter_next (&iter, &child))
17087  *     {
17088  *       /&ast; do something with child &ast;/
17089  *     }
17090  * ]|
17091  *
17092  * Since: 1.10
17093  */
17094 void
17095 clutter_actor_iter_init (ClutterActorIter *iter,
17096                          ClutterActor     *root)
17097 {
17098   RealActorIter *ri = (RealActorIter *) iter;
17099
17100   g_return_if_fail (iter != NULL);
17101   g_return_if_fail (CLUTTER_IS_ACTOR (root));
17102
17103   ri->root = root;
17104   ri->current = NULL;
17105   ri->age = root->priv->age;
17106 }
17107
17108 /**
17109  * clutter_actor_iter_next:
17110  * @iter: a #ClutterActorIter
17111  * @child: (out): return location for a #ClutterActor
17112  *
17113  * Advances the @iter and retrieves the next child of the root #ClutterActor
17114  * that was used to initialize the #ClutterActorIterator.
17115  *
17116  * If the iterator can advance, this function returns %TRUE and sets the
17117  * @child argument.
17118  *
17119  * If the iterator cannot advance, this function returns %FALSE, and
17120  * the contents of @child are undefined.
17121  *
17122  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17123  *
17124  * Since: 1.10
17125  */
17126 gboolean
17127 clutter_actor_iter_next (ClutterActorIter  *iter,
17128                          ClutterActor     **child)
17129 {
17130   RealActorIter *ri = (RealActorIter *) iter;
17131
17132   g_return_val_if_fail (iter != NULL, FALSE);
17133   g_return_val_if_fail (ri->root != NULL, FALSE);
17134 #ifndef G_DISABLE_ASSERT
17135   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17136 #endif
17137
17138   if (ri->current == NULL)
17139     ri->current = ri->root->priv->first_child;
17140   else
17141     ri->current = ri->current->priv->next_sibling;
17142
17143   if (child != NULL)
17144     *child = ri->current;
17145
17146   return ri->current != NULL;
17147 }
17148
17149 /**
17150  * clutter_actor_iter_prev:
17151  * @iter: a #ClutterActorIter
17152  * @child: (out): return location for a #ClutterActor
17153  *
17154  * Advances the @iter and retrieves the previous child of the root
17155  * #ClutterActor that was used to initialize the #ClutterActorIterator.
17156  *
17157  * If the iterator can advance, this function returns %TRUE and sets the
17158  * @child argument.
17159  *
17160  * If the iterator cannot advance, this function returns %FALSE, and
17161  * the contents of @child are undefined.
17162  *
17163  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17164  *
17165  * Since: 1.10
17166  */
17167 gboolean
17168 clutter_actor_iter_prev (ClutterActorIter  *iter,
17169                          ClutterActor     **child)
17170 {
17171   RealActorIter *ri = (RealActorIter *) iter;
17172
17173   g_return_val_if_fail (iter != NULL, FALSE);
17174   g_return_val_if_fail (ri->root != NULL, FALSE);
17175 #ifndef G_DISABLE_ASSERT
17176   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17177 #endif
17178
17179   if (ri->current == NULL)
17180     ri->current = ri->root->priv->last_child;
17181   else
17182     ri->current = ri->current->priv->prev_sibling;
17183
17184   if (child != NULL)
17185     *child = ri->current;
17186
17187   return ri->current != NULL;
17188 }
17189
17190 /**
17191  * clutter_actor_iter_remove:
17192  * @iter: a #ClutterActorIter
17193  *
17194  * Safely removes the #ClutterActor currently pointer to by the iterator
17195  * from its parent.
17196  *
17197  * This function can only be called after clutter_actor_iter_next() or
17198  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17199  * than once for the same actor.
17200  *
17201  * This function will call clutter_actor_remove_child() internally.
17202  *
17203  * Since: 1.10
17204  */
17205 void
17206 clutter_actor_iter_remove (ClutterActorIter *iter)
17207 {
17208   RealActorIter *ri = (RealActorIter *) iter;
17209   ClutterActor *cur;
17210
17211   g_return_if_fail (iter != NULL);
17212   g_return_if_fail (ri->root != NULL);
17213 #ifndef G_DISABLE_ASSERT
17214   g_return_if_fail (ri->age == ri->root->priv->age);
17215 #endif
17216   g_return_if_fail (ri->current != NULL);
17217
17218   cur = ri->current;
17219
17220   if (cur != NULL)
17221     {
17222       ri->current = cur->priv->prev_sibling;
17223
17224       clutter_actor_remove_child_internal (ri->root, cur,
17225                                            REMOVE_CHILD_DEFAULT_FLAGS);
17226
17227       ri->age += 1;
17228     }
17229 }
17230
17231 /**
17232  * clutter_actor_iter_destroy:
17233  * @iter: a #ClutterActorIter
17234  *
17235  * Safely destroys the #ClutterActor currently pointer to by the iterator
17236  * from its parent.
17237  *
17238  * This function can only be called after clutter_actor_iter_next() or
17239  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17240  * than once for the same actor.
17241  *
17242  * This function will call clutter_actor_destroy() internally.
17243  *
17244  * Since: 1.10
17245  */
17246 void
17247 clutter_actor_iter_destroy (ClutterActorIter *iter)
17248 {
17249   RealActorIter *ri = (RealActorIter *) iter;
17250   ClutterActor *cur;
17251
17252   g_return_if_fail (iter != NULL);
17253   g_return_if_fail (ri->root != NULL);
17254 #ifndef G_DISABLE_ASSERT
17255   g_return_if_fail (ri->age == ri->root->priv->age);
17256 #endif
17257   g_return_if_fail (ri->current != NULL);
17258
17259   cur = ri->current;
17260
17261   if (cur != NULL)
17262     {
17263       ri->current = cur->priv->prev_sibling;
17264
17265       clutter_actor_destroy (cur);
17266
17267       ri->age += 1;
17268     }
17269 }
17270
17271 static const ClutterAnimationInfo default_animation_info = {
17272   NULL,         /* transitions */
17273   NULL,         /* states */
17274   NULL,         /* cur_state */
17275 };
17276
17277 static void
17278 clutter_animation_info_free (gpointer data)
17279 {
17280   if (data != NULL)
17281     {
17282       ClutterAnimationInfo *info = data;
17283
17284       if (info->transitions != NULL)
17285         g_hash_table_unref (info->transitions);
17286
17287       if (info->states != NULL)
17288         g_array_unref (info->states);
17289
17290       g_slice_free (ClutterAnimationInfo, info);
17291     }
17292 }
17293
17294 const ClutterAnimationInfo *
17295 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17296 {
17297   const ClutterAnimationInfo *res;
17298   GObject *obj = G_OBJECT (self);
17299
17300   res = g_object_get_qdata (obj, quark_actor_animation_info);
17301   if (res != NULL)
17302     return res;
17303
17304   return &default_animation_info;
17305 }
17306
17307 ClutterAnimationInfo *
17308 _clutter_actor_get_animation_info (ClutterActor *self)
17309 {
17310   GObject *obj = G_OBJECT (self);
17311   ClutterAnimationInfo *res;
17312
17313   res = g_object_get_qdata (obj, quark_actor_animation_info);
17314   if (res == NULL)
17315     {
17316       res = g_slice_new (ClutterAnimationInfo);
17317
17318       *res = default_animation_info;
17319
17320       g_object_set_qdata_full (obj, quark_actor_animation_info,
17321                                res,
17322                                clutter_animation_info_free);
17323     }
17324
17325   return res;
17326 }
17327
17328 ClutterTransition *
17329 _clutter_actor_get_transition (ClutterActor *actor,
17330                                GParamSpec   *pspec)
17331 {
17332   const ClutterAnimationInfo *info;
17333
17334   info = _clutter_actor_get_animation_info_or_defaults (actor);
17335
17336   if (info->transitions == NULL)
17337     return NULL;
17338
17339   return g_hash_table_lookup (info->transitions, pspec->name);
17340 }
17341
17342 static void
17343 transition_closure_free (gpointer data)
17344 {
17345   if (G_LIKELY (data != NULL))
17346     {
17347       TransitionClosure *clos = data;
17348       ClutterTimeline *timeline;
17349
17350       timeline = CLUTTER_TIMELINE (clos->transition);
17351
17352       if (clutter_timeline_is_playing (timeline))
17353         clutter_timeline_stop (timeline);
17354
17355       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17356
17357       g_object_unref (clos->transition);
17358       g_free (clos->name);
17359
17360       g_slice_free (TransitionClosure, clos);
17361     }
17362 }
17363
17364 static void
17365 on_transition_stopped (ClutterTransition *transition,
17366                        gboolean           is_finished,
17367                        TransitionClosure *clos)
17368 {
17369   ClutterActor *actor = clos->actor;
17370   ClutterAnimationInfo *info;
17371
17372   /* reset the caches used by animations */
17373   clutter_actor_store_content_box (actor, NULL);
17374
17375   if (!is_finished)
17376     return;
17377
17378   info = _clutter_actor_get_animation_info (actor);
17379
17380   /* we take a reference here because removing the closure
17381    * will release the reference on the transition, and we
17382    * want the transition to survive the signal emission;
17383    * the master clock will release the last reference at
17384    * the end of the frame processing.
17385    */
17386   g_object_ref (transition);
17387   g_hash_table_remove (info->transitions, clos->name);
17388
17389   /* if it's the last transition then we clean up */
17390   if (g_hash_table_size (info->transitions) == 0)
17391     {
17392       g_hash_table_unref (info->transitions);
17393       info->transitions = NULL;
17394
17395       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17396                     _clutter_actor_get_debug_name (actor));
17397
17398       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17399     }
17400 }
17401
17402 void
17403 _clutter_actor_update_transition (ClutterActor *actor,
17404                                   GParamSpec   *pspec,
17405                                   ...)
17406 {
17407   TransitionClosure *clos;
17408   ClutterTimeline *timeline;
17409   ClutterInterval *interval;
17410   const ClutterAnimationInfo *info;
17411   va_list var_args;
17412   GType ptype;
17413   GValue initial = G_VALUE_INIT;
17414   GValue final = G_VALUE_INIT;
17415   char *error = NULL;
17416
17417   info = _clutter_actor_get_animation_info_or_defaults (actor);
17418
17419   if (info->transitions == NULL)
17420     return;
17421
17422   clos = g_hash_table_lookup (info->transitions, pspec->name);
17423   if (clos == NULL)
17424     return;
17425
17426   timeline = CLUTTER_TIMELINE (clos->transition);
17427
17428   va_start (var_args, pspec);
17429
17430   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17431
17432   g_value_init (&initial, ptype);
17433   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17434                                         pspec->name,
17435                                         &initial);
17436
17437   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17438   if (error != NULL)
17439     {
17440       g_critical ("%s: %s", G_STRLOC, error);
17441       g_free (error);
17442       goto out;
17443     }
17444
17445   interval = clutter_transition_get_interval (clos->transition);
17446   clutter_interval_set_initial_value (interval, &initial);
17447   clutter_interval_set_final_value (interval, &final);
17448
17449   /* if we're updating with an easing duration of zero milliseconds,
17450    * we just jump the timeline to the end and let it run its course
17451    */
17452   if (info->cur_state != NULL &&
17453       info->cur_state->easing_duration != 0)
17454     {
17455       guint cur_duration = clutter_timeline_get_duration (timeline);
17456       ClutterAnimationMode cur_mode =
17457         clutter_timeline_get_progress_mode (timeline);
17458
17459       if (cur_duration != info->cur_state->easing_duration)
17460         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17461
17462       if (cur_mode != info->cur_state->easing_mode)
17463         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17464
17465       clutter_timeline_rewind (timeline);
17466     }
17467   else
17468     {
17469       guint duration = clutter_timeline_get_duration (timeline);
17470
17471       clutter_timeline_advance (timeline, duration);
17472     }
17473
17474 out:
17475   g_value_unset (&initial);
17476   g_value_unset (&final);
17477
17478   va_end (var_args);
17479 }
17480
17481 /*< private >*
17482  * _clutter_actor_create_transition:
17483  * @actor: a #ClutterActor
17484  * @pspec: the property used for the transition
17485  * @...: initial and final state
17486  *
17487  * Creates a #ClutterTransition for the property represented by @pspec.
17488  *
17489  * Return value: a #ClutterTransition
17490  */
17491 ClutterTransition *
17492 _clutter_actor_create_transition (ClutterActor *actor,
17493                                   GParamSpec   *pspec,
17494                                   ...)
17495 {
17496   ClutterAnimationInfo *info;
17497   ClutterTransition *res = NULL;
17498   gboolean call_restore = FALSE;
17499   TransitionClosure *clos;
17500   va_list var_args;
17501
17502   info = _clutter_actor_get_animation_info (actor);
17503
17504   /* XXX - this will go away in 2.0
17505    *
17506    * if no state has been pushed, we assume that the easing state is
17507    * in "compatibility mode": all transitions have a duration of 0
17508    * msecs, which means that they happen immediately. in Clutter 2.0
17509    * this will turn into a g_assert(info->states != NULL), as every
17510    * actor will start with a predefined easing state
17511    */
17512   if (info->states == NULL)
17513     {
17514       clutter_actor_save_easing_state (actor);
17515       clutter_actor_set_easing_duration (actor, 0);
17516       call_restore = TRUE;
17517     }
17518
17519   if (info->transitions == NULL)
17520     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17521                                                NULL,
17522                                                transition_closure_free);
17523
17524   va_start (var_args, pspec);
17525
17526   clos = g_hash_table_lookup (info->transitions, pspec->name);
17527   if (clos == NULL)
17528     {
17529       ClutterTimeline *timeline;
17530       ClutterInterval *interval;
17531       GValue initial = G_VALUE_INIT;
17532       GValue final = G_VALUE_INIT;
17533       GType ptype;
17534       char *error;
17535
17536       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17537
17538       G_VALUE_COLLECT_INIT (&initial, ptype,
17539                             var_args, 0,
17540                             &error);
17541       if (error != NULL)
17542         {
17543           g_critical ("%s: %s", G_STRLOC, error);
17544           g_free (error);
17545           goto out;
17546         }
17547
17548       G_VALUE_COLLECT_INIT (&final, ptype,
17549                             var_args, 0,
17550                             &error);
17551
17552       if (error != NULL)
17553         {
17554           g_critical ("%s: %s", G_STRLOC, error);
17555           g_value_unset (&initial);
17556           g_free (error);
17557           goto out;
17558         }
17559
17560       /* if the current easing state has a duration of 0, then we don't
17561        * bother to create the transition, and we just set the final value
17562        * directly on the actor; we don't go through the Animatable
17563        * interface because we know we got here through an animatable
17564        * property.
17565        */
17566       if (info->cur_state->easing_duration == 0)
17567         {
17568           clutter_actor_set_animatable_property (actor,
17569                                                  pspec->param_id,
17570                                                  &final,
17571                                                  pspec);
17572           g_value_unset (&initial);
17573           g_value_unset (&final);
17574
17575           goto out;
17576         }
17577
17578       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17579
17580       g_value_unset (&initial);
17581       g_value_unset (&final);
17582
17583       res = clutter_property_transition_new (pspec->name);
17584
17585       clutter_transition_set_interval (res, interval);
17586       clutter_transition_set_remove_on_complete (res, TRUE);
17587
17588       timeline = CLUTTER_TIMELINE (res);
17589       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17590       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17591       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17592
17593       CLUTTER_NOTE (ANIMATION,
17594                     "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17595                     _clutter_actor_get_debug_name (actor),
17596                     pspec->name,
17597                     info->cur_state->easing_duration,
17598                     clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17599                     info->cur_state->easing_delay);
17600
17601       /* this will start the transition as well */
17602       clutter_actor_add_transition (actor, pspec->name, res);
17603
17604       /* the actor now owns the transition */
17605       g_object_unref (res);
17606     }
17607   else
17608     res = clos->transition;
17609
17610 out:
17611   if (call_restore)
17612     clutter_actor_restore_easing_state (actor);
17613
17614   va_end (var_args);
17615
17616   return res;
17617 }
17618
17619 /**
17620  * clutter_actor_add_transition:
17621  * @self: a #ClutterActor
17622  * @name: the name of the transition to add
17623  * @transition: the #ClutterTransition to add
17624  *
17625  * Adds a @transition to the #ClutterActor's list of animations.
17626  *
17627  * The @name string is a per-actor unique identifier of the @transition: only
17628  * one #ClutterTransition can be associated to the specified @name.
17629  *
17630  * The @transition will be started once added.
17631  *
17632  * This function will take a reference on the @transition.
17633  *
17634  * This function is usually called implicitly when modifying an animatable
17635  * property.
17636  *
17637  * Since: 1.10
17638  */
17639 void
17640 clutter_actor_add_transition (ClutterActor      *self,
17641                               const char        *name,
17642                               ClutterTransition *transition)
17643 {
17644   ClutterTimeline *timeline;
17645   TransitionClosure *clos;
17646   ClutterAnimationInfo *info;
17647
17648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17649   g_return_if_fail (name != NULL);
17650   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17651
17652   info = _clutter_actor_get_animation_info (self);
17653
17654   if (info->transitions == NULL)
17655     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17656                                                NULL,
17657                                                transition_closure_free);
17658
17659   if (g_hash_table_lookup (info->transitions, name) != NULL)
17660     {
17661       g_warning ("A transition with name '%s' already exists for "
17662                  "the actor '%s'",
17663                  name,
17664                  _clutter_actor_get_debug_name (self));
17665       return;
17666     }
17667
17668   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17669
17670   timeline = CLUTTER_TIMELINE (transition);
17671
17672   clos = g_slice_new (TransitionClosure);
17673   clos->actor = self;
17674   clos->transition = g_object_ref (transition);
17675   clos->name = g_strdup (name);
17676   clos->completed_id = g_signal_connect (timeline, "stopped",
17677                                          G_CALLBACK (on_transition_stopped),
17678                                          clos);
17679
17680   CLUTTER_NOTE (ANIMATION,
17681                 "Adding transition '%s' [%p] to actor '%s'",
17682                 clos->name,
17683                 clos->transition,
17684                 _clutter_actor_get_debug_name (self));
17685
17686   g_hash_table_insert (info->transitions, clos->name, clos);
17687   clutter_timeline_start (timeline);
17688 }
17689
17690 /**
17691  * clutter_actor_remove_transition:
17692  * @self: a #ClutterActor
17693  * @name: the name of the transition to remove
17694  *
17695  * Removes the transition stored inside a #ClutterActor using @name
17696  * identifier.
17697  *
17698  * If the transition is currently in progress, it will be stopped.
17699  *
17700  * This function releases the reference acquired when the transition
17701  * was added to the #ClutterActor.
17702  *
17703  * Since: 1.10
17704  */
17705 void
17706 clutter_actor_remove_transition (ClutterActor *self,
17707                                  const char   *name)
17708 {
17709   const ClutterAnimationInfo *info;
17710
17711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17712   g_return_if_fail (name != NULL);
17713
17714   info = _clutter_actor_get_animation_info_or_defaults (self);
17715
17716   if (info->transitions == NULL)
17717     return;
17718
17719   g_hash_table_remove (info->transitions, name);
17720 }
17721
17722 /**
17723  * clutter_actor_remove_all_transitions:
17724  * @self: a #ClutterActor
17725  *
17726  * Removes all transitions associated to @self.
17727  *
17728  * Since: 1.10
17729  */
17730 void
17731 clutter_actor_remove_all_transitions (ClutterActor *self)
17732 {
17733   const ClutterAnimationInfo *info;
17734
17735   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17736
17737   info = _clutter_actor_get_animation_info_or_defaults (self);
17738   if (info->transitions == NULL)
17739     return;
17740
17741   g_hash_table_remove_all (info->transitions);
17742 }
17743
17744 /**
17745  * clutter_actor_set_easing_duration:
17746  * @self: a #ClutterActor
17747  * @msecs: the duration of the easing, or %NULL
17748  *
17749  * Sets the duration of the tweening for animatable properties
17750  * of @self for the current easing state.
17751  *
17752  * Since: 1.10
17753  */
17754 void
17755 clutter_actor_set_easing_duration (ClutterActor *self,
17756                                    guint         msecs)
17757 {
17758   ClutterAnimationInfo *info;
17759
17760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17761
17762   info = _clutter_actor_get_animation_info (self);
17763
17764   if (info->cur_state == NULL)
17765     {
17766       g_warning ("You must call clutter_actor_save_easing_state() prior "
17767                  "to calling clutter_actor_set_easing_duration().");
17768       return;
17769     }
17770
17771   if (info->cur_state->easing_duration != msecs)
17772     info->cur_state->easing_duration = msecs;
17773 }
17774
17775 /**
17776  * clutter_actor_get_easing_duration:
17777  * @self: a #ClutterActor
17778  *
17779  * Retrieves the duration of the tweening for animatable
17780  * properties of @self for the current easing state.
17781  *
17782  * Return value: the duration of the tweening, in milliseconds
17783  *
17784  * Since: 1.10
17785  */
17786 guint
17787 clutter_actor_get_easing_duration (ClutterActor *self)
17788 {
17789   const ClutterAnimationInfo *info;
17790
17791   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17792
17793   info = _clutter_actor_get_animation_info_or_defaults (self);
17794
17795   if (info->cur_state != NULL)
17796     return info->cur_state->easing_duration;
17797
17798   return 0;
17799 }
17800
17801 /**
17802  * clutter_actor_set_easing_mode:
17803  * @self: a #ClutterActor
17804  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17805  *
17806  * Sets the easing mode for the tweening of animatable properties
17807  * of @self.
17808  *
17809  * Since: 1.10
17810  */
17811 void
17812 clutter_actor_set_easing_mode (ClutterActor         *self,
17813                                ClutterAnimationMode  mode)
17814 {
17815   ClutterAnimationInfo *info;
17816
17817   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17818   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17819   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17820
17821   info = _clutter_actor_get_animation_info (self);
17822
17823   if (info->cur_state == NULL)
17824     {
17825       g_warning ("You must call clutter_actor_save_easing_state() prior "
17826                  "to calling clutter_actor_set_easing_mode().");
17827       return;
17828     }
17829
17830   if (info->cur_state->easing_mode != mode)
17831     info->cur_state->easing_mode = mode;
17832 }
17833
17834 /**
17835  * clutter_actor_get_easing_mode:
17836  * @self: a #ClutterActor
17837  *
17838  * Retrieves the easing mode for the tweening of animatable properties
17839  * of @self for the current easing state.
17840  *
17841  * Return value: an easing mode
17842  *
17843  * Since: 1.10
17844  */
17845 ClutterAnimationMode
17846 clutter_actor_get_easing_mode (ClutterActor *self)
17847 {
17848   const ClutterAnimationInfo *info;
17849
17850   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17851
17852   info = _clutter_actor_get_animation_info_or_defaults (self);
17853
17854   if (info->cur_state != NULL)
17855     return info->cur_state->easing_mode;
17856
17857   return CLUTTER_EASE_OUT_CUBIC;
17858 }
17859
17860 /**
17861  * clutter_actor_set_easing_delay:
17862  * @self: a #ClutterActor
17863  * @msecs: the delay before the start of the tweening, in milliseconds
17864  *
17865  * Sets the delay that should be applied before tweening animatable
17866  * properties.
17867  *
17868  * Since: 1.10
17869  */
17870 void
17871 clutter_actor_set_easing_delay (ClutterActor *self,
17872                                 guint         msecs)
17873 {
17874   ClutterAnimationInfo *info;
17875
17876   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17877
17878   info = _clutter_actor_get_animation_info (self);
17879
17880   if (info->cur_state == NULL)
17881     {
17882       g_warning ("You must call clutter_actor_save_easing_state() prior "
17883                  "to calling clutter_actor_set_easing_delay().");
17884       return;
17885     }
17886
17887   if (info->cur_state->easing_delay != msecs)
17888     info->cur_state->easing_delay = msecs;
17889 }
17890
17891 /**
17892  * clutter_actor_get_easing_delay:
17893  * @self: a #ClutterActor
17894  *
17895  * Retrieves the delay that should be applied when tweening animatable
17896  * properties.
17897  *
17898  * Return value: a delay, in milliseconds
17899  *
17900  * Since: 1.10
17901  */
17902 guint
17903 clutter_actor_get_easing_delay (ClutterActor *self)
17904 {
17905   const ClutterAnimationInfo *info;
17906
17907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17908
17909   info = _clutter_actor_get_animation_info_or_defaults (self);
17910
17911   if (info->cur_state != NULL)
17912     return info->cur_state->easing_delay;
17913
17914   return 0;
17915 }
17916
17917 /**
17918  * clutter_actor_get_transition:
17919  * @self: a #ClutterActor
17920  * @name: the name of the transition
17921  *
17922  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17923  * transition @name.
17924  *
17925  * Transitions created for animatable properties use the name of the
17926  * property itself, for instance the code below:
17927  *
17928  * |[
17929  *   clutter_actor_set_easing_duration (actor, 1000);
17930  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17931  *
17932  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17933  *   g_signal_connect (transition, "stopped",
17934  *                     G_CALLBACK (on_transition_stopped),
17935  *                     actor);
17936  * ]|
17937  *
17938  * will call the <function>on_transition_stopped</function> callback when
17939  * the transition is finished.
17940  *
17941  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17942  *   was found to match the passed name; the returned instance is owned
17943  *   by Clutter and it should not be freed
17944  *
17945  * Since: 1.10
17946  */
17947 ClutterTransition *
17948 clutter_actor_get_transition (ClutterActor *self,
17949                               const char   *name)
17950 {
17951   TransitionClosure *clos;
17952   const ClutterAnimationInfo *info;
17953
17954   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17955   g_return_val_if_fail (name != NULL, NULL);
17956
17957   info = _clutter_actor_get_animation_info_or_defaults (self);
17958   if (info->transitions == NULL)
17959     return NULL;
17960
17961   clos = g_hash_table_lookup (info->transitions, name);
17962   if (clos == NULL)
17963     return NULL;
17964
17965   return clos->transition;
17966 }
17967
17968 /**
17969  * clutter_actor_save_easing_state:
17970  * @self: a #ClutterActor
17971  *
17972  * Saves the current easing state for animatable properties, and creates
17973  * a new state with the default values for easing mode and duration.
17974  *
17975  * Since: 1.10
17976  */
17977 void
17978 clutter_actor_save_easing_state (ClutterActor *self)
17979 {
17980   ClutterAnimationInfo *info;
17981   AState new_state;
17982
17983   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17984
17985   info = _clutter_actor_get_animation_info (self);
17986
17987   if (info->states == NULL)
17988     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17989
17990   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17991   new_state.easing_duration = 250;
17992   new_state.easing_delay = 0;
17993
17994   g_array_append_val (info->states, new_state);
17995
17996   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17997 }
17998
17999 /**
18000  * clutter_actor_restore_easing_state:
18001  * @self: a #ClutterActor
18002  *
18003  * Restores the easing state as it was prior to a call to
18004  * clutter_actor_save_easing_state().
18005  *
18006  * Since: 1.10
18007  */
18008 void
18009 clutter_actor_restore_easing_state (ClutterActor *self)
18010 {
18011   ClutterAnimationInfo *info;
18012
18013   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18014
18015   info = _clutter_actor_get_animation_info (self);
18016
18017   if (info->states == NULL)
18018     {
18019       g_critical ("The function clutter_actor_restore_easing_state() has "
18020                   "called without a previous call to "
18021                   "clutter_actor_save_easing_state().");
18022       return;
18023     }
18024
18025   g_array_remove_index (info->states, info->states->len - 1);
18026
18027   if (info->states->len > 0)
18028     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
18029   else
18030     {
18031       g_array_unref (info->states);
18032       info->states = NULL;
18033       info->cur_state = NULL;
18034     }
18035 }
18036
18037 /**
18038  * clutter_actor_set_content:
18039  * @self: a #ClutterActor
18040  * @content: (allow-none): a #ClutterContent, or %NULL
18041  *
18042  * Sets the contents of a #ClutterActor.
18043  *
18044  * Since: 1.10
18045  */
18046 void
18047 clutter_actor_set_content (ClutterActor   *self,
18048                            ClutterContent *content)
18049 {
18050   ClutterActorPrivate *priv;
18051
18052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18053   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18054
18055   priv = self->priv;
18056
18057   if (priv->content != NULL)
18058     {
18059       _clutter_content_detached (priv->content, self);
18060       g_clear_object (&priv->content);
18061     }
18062
18063   priv->content = content;
18064
18065   if (priv->content != NULL)
18066     {
18067       g_object_ref (priv->content);
18068       _clutter_content_attached (priv->content, self);
18069     }
18070
18071   /* given that the content is always painted within the allocation,
18072    * we only need to queue a redraw here
18073    */
18074   clutter_actor_queue_redraw (self);
18075
18076   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18077
18078   /* if the content gravity is not resize-fill, and the new content has a
18079    * different preferred size than the previous one, then the content box
18080    * may have been changed. since we compute that lazily, we just notify
18081    * here, and let whomever watches :content-box do whatever they need to
18082    * do.
18083    */
18084   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18085     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18086 }
18087
18088 /**
18089  * clutter_actor_get_content:
18090  * @self: a #ClutterActor
18091  *
18092  * Retrieves the contents of @self.
18093  *
18094  * Return value: (transfer none): a pointer to the #ClutterContent instance,
18095  *   or %NULL if none was set
18096  *
18097  * Since: 1.10
18098  */
18099 ClutterContent *
18100 clutter_actor_get_content (ClutterActor *self)
18101 {
18102   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18103
18104   return self->priv->content;
18105 }
18106
18107 /**
18108  * clutter_actor_set_content_gravity:
18109  * @self: a #ClutterActor
18110  * @gravity: the #ClutterContentGravity
18111  *
18112  * Sets the gravity of the #ClutterContent used by @self.
18113  *
18114  * See the description of the #ClutterActor:content-gravity property for
18115  * more information.
18116  *
18117  * The #ClutterActor:content-gravity property is animatable.
18118  *
18119  * Since: 1.10
18120  */
18121 void
18122 clutter_actor_set_content_gravity (ClutterActor *self,
18123                                    ClutterContentGravity  gravity)
18124 {
18125   ClutterActorPrivate *priv;
18126
18127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18128
18129   priv = self->priv;
18130
18131   if (priv->content_gravity == gravity)
18132     return;
18133
18134   priv->content_box_valid = FALSE;
18135
18136   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18137     {
18138       ClutterActorBox from_box, to_box;
18139
18140       clutter_actor_get_content_box (self, &from_box);
18141
18142       priv->content_gravity = gravity;
18143
18144       clutter_actor_get_content_box (self, &to_box);
18145
18146       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18147                                         &from_box,
18148                                         &to_box);
18149     }
18150   else
18151     {
18152       ClutterActorBox to_box;
18153
18154       priv->content_gravity = gravity;
18155
18156       clutter_actor_get_content_box (self, &to_box);
18157
18158       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18159                                         &to_box);
18160     }
18161
18162   clutter_actor_queue_redraw (self);
18163
18164   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18165 }
18166
18167 /**
18168  * clutter_actor_get_content_gravity:
18169  * @self: a #ClutterActor
18170  *
18171  * Retrieves the content gravity as set using
18172  * clutter_actor_get_content_gravity().
18173  *
18174  * Return value: the content gravity
18175  *
18176  * Since: 1.10
18177  */
18178 ClutterContentGravity
18179 clutter_actor_get_content_gravity (ClutterActor *self)
18180 {
18181   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18182                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18183
18184   return self->priv->content_gravity;
18185 }
18186
18187 /**
18188  * clutter_actor_get_content_box:
18189  * @self: a #ClutterActor
18190  * @box: (out caller-allocates): the return location for the bounding
18191  *   box for the #ClutterContent
18192  *
18193  * Retrieves the bounding box for the #ClutterContent of @self.
18194  *
18195  * The bounding box is relative to the actor's allocation.
18196  *
18197  * If no #ClutterContent is set for @self, or if @self has not been
18198  * allocated yet, then the result is undefined.
18199  *
18200  * The content box is guaranteed to be, at most, as big as the allocation
18201  * of the #ClutterActor.
18202  *
18203  * If the #ClutterContent used by the actor has a preferred size, then
18204  * it is possible to modify the content box by using the
18205  * #ClutterActor:content-gravity property.
18206  *
18207  * Since: 1.10
18208  */
18209 void
18210 clutter_actor_get_content_box (ClutterActor    *self,
18211                                ClutterActorBox *box)
18212 {
18213   ClutterActorPrivate *priv;
18214   gfloat content_w, content_h;
18215   gfloat alloc_w, alloc_h;
18216
18217   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18218   g_return_if_fail (box != NULL);
18219
18220   priv = self->priv;
18221
18222   box->x1 = 0.f;
18223   box->y1 = 0.f;
18224   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18225   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18226
18227   if (priv->content_box_valid)
18228     {
18229       *box = priv->content_box;
18230       return;
18231     }
18232
18233   /* no need to do any more work */
18234   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18235     return;
18236
18237   if (priv->content == NULL)
18238     return;
18239
18240   /* if the content does not have a preferred size then there is
18241    * no point in computing the content box
18242    */
18243   if (!clutter_content_get_preferred_size (priv->content,
18244                                            &content_w,
18245                                            &content_h))
18246     return;
18247
18248   alloc_w = box->x2;
18249   alloc_h = box->y2;
18250
18251   switch (priv->content_gravity)
18252     {
18253     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18254       box->x2 = box->x1 + MIN (content_w, alloc_w);
18255       box->y2 = box->y1 + MIN (content_h, alloc_h);
18256       break;
18257
18258     case CLUTTER_CONTENT_GRAVITY_TOP:
18259       if (alloc_w > content_w)
18260         {
18261           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18262           box->x2 = box->x1 + content_w;
18263         }
18264       box->y2 = box->y1 + MIN (content_h, alloc_h);
18265       break;
18266
18267     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18268       if (alloc_w > content_w)
18269         {
18270           box->x1 += (alloc_w - content_w);
18271           box->x2 = box->x1 + content_w;
18272         }
18273       box->y2 = box->y1 + MIN (content_h, alloc_h);
18274       break;
18275
18276     case CLUTTER_CONTENT_GRAVITY_LEFT:
18277       box->x2 = box->x1 + MIN (content_w, alloc_w);
18278       if (alloc_h > content_h)
18279         {
18280           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18281           box->y2 = box->y1 + content_h;
18282         }
18283       break;
18284
18285     case CLUTTER_CONTENT_GRAVITY_CENTER:
18286       if (alloc_w > content_w)
18287         {
18288           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18289           box->x2 = box->x1 + content_w;
18290         }
18291       if (alloc_h > content_h)
18292         {
18293           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18294           box->y2 = box->y1 + content_h;
18295         }
18296       break;
18297
18298     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18299       if (alloc_w > content_w)
18300         {
18301           box->x1 += (alloc_w - content_w);
18302           box->x2 = box->x1 + content_w;
18303         }
18304       if (alloc_h > content_h)
18305         {
18306           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18307           box->y2 = box->y1 + content_h;
18308         }
18309       break;
18310
18311     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18312       box->x2 = box->x1 + MIN (content_w, alloc_w);
18313       if (alloc_h > content_h)
18314         {
18315           box->y1 += (alloc_h - content_h);
18316           box->y2 = box->y1 + content_h;
18317         }
18318       break;
18319
18320     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18321       if (alloc_w > content_w)
18322         {
18323           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18324           box->x2 = box->x1 + content_w;
18325         }
18326       if (alloc_h > content_h)
18327         {
18328           box->y1 += (alloc_h - content_h);
18329           box->y2 = box->y1 + content_h;
18330         }
18331       break;
18332
18333     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18334       if (alloc_w > content_w)
18335         {
18336           box->x1 += (alloc_w - content_w);
18337           box->x2 = box->x1 + content_w;
18338         }
18339       if (alloc_h > content_h)
18340         {
18341           box->y1 += (alloc_h - content_h);
18342           box->y2 = box->y1 + content_h;
18343         }
18344       break;
18345
18346     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18347       g_assert_not_reached ();
18348       break;
18349
18350     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18351       {
18352         double r_c = content_w / content_h;
18353
18354         if (r_c >= 1.0)
18355           {
18356             if ((alloc_w / r_c) > alloc_h)
18357               {
18358                 box->x1 = 0.f;
18359                 box->x2 = alloc_w;
18360
18361                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18362                 box->y2 = box->y1 + (alloc_w / r_c);
18363               }
18364             else
18365               {
18366                 box->y1 = 0.f;
18367                 box->y2 = alloc_h;
18368
18369                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18370                 box->x2 = box->x1 + (alloc_h * r_c);
18371               }
18372           }
18373         else
18374           {
18375             if ((alloc_w / r_c) > alloc_h)
18376               {
18377                 box->y1 = 0.f;
18378                 box->y2 = alloc_h;
18379
18380                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18381                 box->x2 = box->x1 + (alloc_h * r_c);
18382               }
18383             else
18384               {
18385                 box->x1 = 0.f;
18386                 box->x2 = alloc_w;
18387
18388                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18389                 box->y2 = box->y1 + (alloc_w / r_c);
18390               }
18391           }
18392
18393         CLUTTER_NOTE (LAYOUT,
18394                       "r_c: %.3f, r_a: %.3f\t"
18395                       "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18396                       "b: [%.2f, %.2f, %.2f, %.2f]",
18397                       r_c, alloc_w / alloc_h,
18398                       alloc_w, alloc_h,
18399                       content_w, content_h,
18400                       box->x1, box->y1, box->x2, box->y2);
18401       }
18402       break;
18403     }
18404 }
18405
18406 /**
18407  * clutter_actor_set_content_scaling_filters:
18408  * @self: a #ClutterActor
18409  * @min_filter: the minification filter for the content
18410  * @mag_filter: the magnification filter for the content
18411  *
18412  * Sets the minification and magnification filter to be applied when
18413  * scaling the #ClutterActor:content of a #ClutterActor.
18414  *
18415  * The #ClutterActor:minification-filter will be used when reducing
18416  * the size of the content; the #ClutterActor:magnification-filter
18417  * will be used when increasing the size of the content.
18418  *
18419  * Since: 1.10
18420  */
18421 void
18422 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18423                                            ClutterScalingFilter  min_filter,
18424                                            ClutterScalingFilter  mag_filter)
18425 {
18426   ClutterActorPrivate *priv;
18427   gboolean changed;
18428   GObject *obj;
18429
18430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18431
18432   priv = self->priv;
18433   obj = G_OBJECT (self);
18434
18435   g_object_freeze_notify (obj);
18436
18437   changed = FALSE;
18438
18439   if (priv->min_filter != min_filter)
18440     {
18441       priv->min_filter = min_filter;
18442       changed = TRUE;
18443
18444       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18445     }
18446
18447   if (priv->mag_filter != mag_filter)
18448     {
18449       priv->mag_filter = mag_filter;
18450       changed = TRUE;
18451
18452       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18453     }
18454
18455   if (changed)
18456     clutter_actor_queue_redraw (self);
18457
18458   g_object_thaw_notify (obj);
18459 }
18460
18461 /**
18462  * clutter_actor_get_content_scaling_filters:
18463  * @self: a #ClutterActor
18464  * @min_filter: (out) (allow-none): return location for the minification
18465  *   filter, or %NULL
18466  * @mag_filter: (out) (allow-none): return location for the magnification
18467  *   filter, or %NULL
18468  *
18469  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18470  *
18471  * Since: 1.10
18472  */
18473 void
18474 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18475                                            ClutterScalingFilter *min_filter,
18476                                            ClutterScalingFilter *mag_filter)
18477 {
18478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18479
18480   if (min_filter != NULL)
18481     *min_filter = self->priv->min_filter;
18482
18483   if (mag_filter != NULL)
18484     *mag_filter = self->priv->mag_filter;
18485 }
18486
18487 /*
18488  * clutter_actor_queue_compute_expand:
18489  * @self: a #ClutterActor
18490  *
18491  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18492  * and its parents up to the top-level actor.
18493  *
18494  * This function also queues a relayout if anything changed.
18495  */
18496 static inline void
18497 clutter_actor_queue_compute_expand (ClutterActor *self)
18498 {
18499   ClutterActor *parent;
18500   gboolean changed;
18501
18502   if (self->priv->needs_compute_expand)
18503     return;
18504
18505   changed = FALSE;
18506   parent = self;
18507   while (parent != NULL)
18508     {
18509       if (!parent->priv->needs_compute_expand)
18510         {
18511           parent->priv->needs_compute_expand = TRUE;
18512           changed = TRUE;
18513         }
18514
18515       parent = parent->priv->parent;
18516     }
18517
18518   if (changed)
18519     clutter_actor_queue_relayout (self);
18520 }
18521
18522 /**
18523  * clutter_actor_set_x_expand:
18524  * @self: a #ClutterActor
18525  * @expand: whether the actor should expand horizontally
18526  *
18527  * Sets whether a #ClutterActor should expand horizontally; this means
18528  * that layout manager should allocate extra space for the actor, if
18529  * possible.
18530  *
18531  * Setting an actor to expand will also make all its parent expand, so
18532  * that it's possible to build an actor tree and only set this flag on
18533  * its leaves and not on every single actor.
18534  *
18535  * Since: 1.12
18536  */
18537 void
18538 clutter_actor_set_x_expand (ClutterActor *self,
18539                             gboolean      expand)
18540 {
18541   ClutterLayoutInfo *info;
18542
18543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18544
18545   expand = !!expand;
18546
18547   info = _clutter_actor_get_layout_info (self);
18548   if (info->x_expand != expand)
18549     {
18550       info->x_expand = expand;
18551
18552       self->priv->x_expand_set = TRUE;
18553
18554       clutter_actor_queue_compute_expand (self);
18555
18556       g_object_notify_by_pspec (G_OBJECT (self),
18557                                 obj_props[PROP_X_EXPAND]);
18558     }
18559 }
18560
18561 /**
18562  * clutter_actor_get_x_expand:
18563  * @self: a #ClutterActor
18564  *
18565  * Retrieves the value set with clutter_actor_set_x_expand().
18566  *
18567  * See also: clutter_actor_needs_expand()
18568  *
18569  * Return value: %TRUE if the actor has been set to expand
18570  *
18571  * Since: 1.12
18572  */
18573 gboolean
18574 clutter_actor_get_x_expand (ClutterActor *self)
18575 {
18576   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18577
18578   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18579 }
18580
18581 /**
18582  * clutter_actor_set_y_expand:
18583  * @self: a #ClutterActor
18584  * @expand: whether the actor should expand vertically
18585  *
18586  * Sets whether a #ClutterActor should expand horizontally; this means
18587  * that layout manager should allocate extra space for the actor, if
18588  * possible.
18589  *
18590  * Setting an actor to expand will also make all its parent expand, so
18591  * that it's possible to build an actor tree and only set this flag on
18592  * its leaves and not on every single actor.
18593  *
18594  * Since: 1.12
18595  */
18596 void
18597 clutter_actor_set_y_expand (ClutterActor *self,
18598                             gboolean      expand)
18599 {
18600   ClutterLayoutInfo *info;
18601
18602   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18603
18604   expand = !!expand;
18605
18606   info = _clutter_actor_get_layout_info (self);
18607   if (info->y_expand != expand)
18608     {
18609       info->y_expand = expand;
18610
18611       self->priv->y_expand_set = TRUE;
18612
18613       clutter_actor_queue_compute_expand (self);
18614
18615       g_object_notify_by_pspec (G_OBJECT (self),
18616                                 obj_props[PROP_Y_EXPAND]);
18617     }
18618 }
18619
18620 /**
18621  * clutter_actor_get_y_expand:
18622  * @self: a #ClutterActor
18623  *
18624  * Retrieves the value set with clutter_actor_set_y_expand().
18625  *
18626  * See also: clutter_actor_needs_expand()
18627  *
18628  * Return value: %TRUE if the actor has been set to expand
18629  *
18630  * Since: 1.12
18631  */
18632 gboolean
18633 clutter_actor_get_y_expand (ClutterActor *self)
18634 {
18635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18636
18637   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18638 }
18639
18640 static void
18641 clutter_actor_compute_expand_recursive (ClutterActor *self,
18642                                         gboolean     *x_expand_p,
18643                                         gboolean     *y_expand_p)
18644 {
18645   ClutterActorIter iter;
18646   ClutterActor *child;
18647   gboolean x_expand, y_expand;
18648
18649   x_expand = y_expand = FALSE;
18650
18651   /* note that we don't recurse into children if we're already set to expand;
18652    * this avoids traversing the whole actor tree, even if it may lead to some
18653    * child left with the needs_compute_expand flag set.
18654    */
18655   clutter_actor_iter_init (&iter, self);
18656   while (clutter_actor_iter_next (&iter, &child))
18657     {
18658       x_expand = x_expand ||
18659         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18660
18661       y_expand = y_expand ||
18662         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18663     }
18664
18665   *x_expand_p = x_expand;
18666   *y_expand_p = y_expand;
18667 }
18668
18669 static void
18670 clutter_actor_compute_expand (ClutterActor *self)
18671 {
18672   if (self->priv->needs_compute_expand)
18673     {
18674       const ClutterLayoutInfo *info;
18675       gboolean x_expand, y_expand;
18676
18677       info = _clutter_actor_get_layout_info_or_defaults (self);
18678
18679       if (self->priv->x_expand_set)
18680         x_expand = info->x_expand;
18681       else
18682         x_expand = FALSE;
18683
18684       if (self->priv->y_expand_set)
18685         y_expand = info->y_expand;
18686       else
18687         y_expand = FALSE;
18688
18689       /* we don't need to recurse down to the children if the
18690        * actor has been forcibly set to expand
18691        */
18692       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18693         {
18694           if (self->priv->n_children != 0)
18695             {
18696               gboolean *x_expand_p, *y_expand_p;
18697               gboolean ignored = FALSE;
18698
18699               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18700               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18701
18702               clutter_actor_compute_expand_recursive (self,
18703                                                       x_expand_p,
18704                                                       y_expand_p);
18705             }
18706         }
18707
18708       self->priv->needs_compute_expand = FALSE;
18709       self->priv->needs_x_expand = (x_expand != FALSE);
18710       self->priv->needs_y_expand = (y_expand != FALSE);
18711     }
18712 }
18713
18714 /**
18715  * clutter_actor_needs_expand:
18716  * @self: a #ClutterActor
18717  * @orientation: the direction of expansion
18718  *
18719  * Checks whether an actor, or any of its children, is set to expand
18720  * horizontally or vertically.
18721  *
18722  * This function should only be called by layout managers that can
18723  * assign extra space to their children.
18724  *
18725  * If you want to know whether the actor was explicitly set to expand,
18726  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18727  *
18728  * Return value: %TRUE if the actor should expand
18729  *
18730  * Since: 1.12
18731  */
18732 gboolean
18733 clutter_actor_needs_expand (ClutterActor       *self,
18734                             ClutterOrientation  orientation)
18735 {
18736   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18737
18738   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18739     return FALSE;
18740
18741   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18742     return FALSE;
18743
18744   clutter_actor_compute_expand (self);
18745
18746   switch (orientation)
18747     {
18748     case CLUTTER_ORIENTATION_HORIZONTAL:
18749       return self->priv->needs_x_expand;
18750
18751     case CLUTTER_ORIENTATION_VERTICAL:
18752       return self->priv->needs_y_expand;
18753     }
18754
18755   return FALSE;
18756 }
18757
18758 /**
18759  * clutter_actor_set_content_repeat:
18760  * @self: a #ClutterActor
18761  * @repeat: the repeat policy
18762  *
18763  * Sets the policy for repeating the #ClutterActor:content of a
18764  * #ClutterActor. The behaviour is deferred to the #ClutterContent
18765  * implementation.
18766  *
18767  * Since: 1.12
18768  */
18769 void
18770 clutter_actor_set_content_repeat (ClutterActor         *self,
18771                                   ClutterContentRepeat  repeat)
18772 {
18773   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18774
18775   if (self->priv->content_repeat == repeat)
18776     return;
18777
18778   self->priv->content_repeat = repeat;
18779
18780   clutter_actor_queue_redraw (self);
18781 }
18782
18783 /**
18784  * clutter_actor_get_content_repeat:
18785  * @self: a #ClutterActor
18786  *
18787  * Retrieves the repeat policy for a #ClutterActor set by
18788  * clutter_actor_set_content_repeat().
18789  *
18790  * Return value: the content repeat policy
18791  *
18792  * Since: 1.12
18793  */
18794 ClutterContentRepeat
18795 clutter_actor_get_content_repeat (ClutterActor *self)
18796 {
18797   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REPEAT_NONE);
18798
18799   return self->priv->content_repeat;
18800 }