actor: Ignore allocation flags
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-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 will also parse every positional and dimensional
387  *   property defined as a string through clutter_units_from_string(); you
388  *   should read the documentation for the #ClutterUnits parser format for
389  *   the valid units and syntax.</para>
390  * </refsect2>
391  *
392  * <refsect2 id="ClutterActor-custom-animatable-properties">
393  *   <title>Custom animatable properties</title>
394  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
395  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
396  *   instance for animation purposes.</para>
397  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
398  *   property it is necessary to set the #ClutterActorMeta:name property on the
399  *   given action or constraint.</para>
400  *   <para>The property can be accessed using the following syntax:</para>
401  *   <informalexample>
402  *     <programlisting>
403  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
404  *     </programlisting>
405  *   </informalexample>
406  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
407  *   <para>The <emphasis>section</emphasis> fragment can be one between
408  *   "actions", "constraints" and "effects".</para>
409  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
410  *   action or constraint, as specified by the #ClutterActorMeta:name
411  *   property.</para>
412  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
413  *   action or constraint property to be animated.</para>
414  *   <para>The example below animates a #ClutterBindConstraint applied to an
415  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
416  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
417  *   its initial state is overlapping the actor to which is bound to.</para>
418  *   <informalexample><programlisting>
419  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
420  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
421  * clutter_actor_add_constraint (rect, constraint);
422  *
423  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
424  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
425  * clutter_actor_add_constraint (rect, constraint);
426  *
427  * clutter_actor_set_reactive (origin, TRUE);
428  *
429  * g_signal_connect (origin, "button-press-event",
430  *                   G_CALLBACK (on_button_press),
431  *                   rect);
432  *   </programlisting></informalexample>
433  *   <para>On button press, the rectangle "slides" from behind the actor to
434  *   which is bound to, using the #ClutterBindConstraint:offset property to
435  *   achieve the effect:</para>
436  *   <informalexample><programlisting>
437  * gboolean
438  * on_button_press (ClutterActor *origin,
439  *                  ClutterEvent *event,
440  *                  ClutterActor *rect)
441  * {
442  *   ClutterTransition *transition;
443  *   ClutterInterval *interval;
444  *
445  *   /&ast; the offset that we want to apply; this will make the actor
446  *    &ast; slide in from behind the origin and rest at the right of
447  *    &ast; the origin, plus a padding value.
448  *    &ast;/
449  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
450  *
451  *   /&ast; the property we wish to animate; the "@constraints" section
452  *    &ast; tells Clutter to check inside the constraints associated
453  *    &ast; with the actor; the "bind-x" section is the name of the
454  *    &ast; constraint; and the "offset" is the name of the property
455  *    &ast; on the constraint.
456  *    &ast;/
457  *   const char *prop = "@constraints.bind-x.offset";
458  *
459  *   /&ast; create a new transition for the given property &ast;/
460  *   transition = clutter_property_transition_new (prop);
461  *
462  *   /&ast; set the easing mode and duration &ast;/
463  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
464  *                                       CLUTTER_EASE_OUT_CUBIC);
465  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
466  *
467  *   /&ast; create the interval with the initial and final values &ast;/
468  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
469  *   clutter_transition_set_interval (transition, interval);
470  *
471  *   /&ast; add the transition to the actor; this causes the animation
472  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
473  *    &ast; the transition later.
474  *    &ast;/
475  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
476  *
477  *   /&ast; we handled the event &ast;/
478  *   return CLUTTER_EVENT_STOP;
479  * }
480  *   </programlisting></informalexample>
481  * </refsect2>
482  */
483
484 /**
485  * CLUTTER_ACTOR_IS_MAPPED:
486  * @a: a #ClutterActor
487  *
488  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
489  *
490  * The mapped state is set when the actor is visible and all its parents up
491  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
492  *
493  * This check can be used to see if an actor is going to be painted, as only
494  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
495  *
496  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
497  * not be checked directly; instead, the recommended usage is to connect a
498  * handler on the #GObject::notify signal for the #ClutterActor:mapped
499  * property of #ClutterActor, and check the presence of
500  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
501  *
502  * It is also important to note that Clutter may delay the changes of
503  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
504  * limitations, or during the reparenting of an actor, to optimize
505  * unnecessary (and potentially expensive) state changes.
506  *
507  * Since: 0.2
508  */
509
510 /**
511  * CLUTTER_ACTOR_IS_REALIZED:
512  * @a: a #ClutterActor
513  *
514  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
515  *
516  * The realized state has an actor-dependant interpretation. If an
517  * actor wants to delay allocating resources until it is attached to a
518  * stage, it may use the realize state to do so. However it is
519  * perfectly acceptable for an actor to allocate Cogl resources before
520  * being realized because there is only one drawing context used by Clutter
521  * so any resources will work on any stage.  If an actor is mapped it
522  * must also be realized, but an actor can be realized and unmapped
523  * (this is so hiding an actor temporarily doesn't do an expensive
524  * unrealize/realize).
525  *
526  * To be realized an actor must be inside a stage, and all its parents
527  * must be realized.
528  *
529  * Since: 0.2
530  */
531
532 /**
533  * CLUTTER_ACTOR_IS_VISIBLE:
534  * @a: a #ClutterActor
535  *
536  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
537  * Equivalent to the ClutterActor::visible object property.
538  *
539  * Note that an actor is only painted onscreen if it's mapped, which
540  * means it's visible, and all its parents are visible, and one of the
541  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
542  *
543  * Since: 0.2
544  */
545
546 /**
547  * CLUTTER_ACTOR_IS_REACTIVE:
548  * @a: a #ClutterActor
549  *
550  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
551  *
552  * Only reactive actors will receive event-related signals.
553  *
554  * Since: 0.6
555  */
556
557 #ifdef HAVE_CONFIG_H
558 #include "config.h"
559 #endif
560
561 #include <math.h>
562
563 #include <gobject/gvaluecollector.h>
564
565 #include <cogl/cogl.h>
566
567 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
568 #define CLUTTER_ENABLE_EXPERIMENTAL_API
569
570 #include "clutter-actor-private.h"
571
572 #include "clutter-action.h"
573 #include "clutter-actor-meta-private.h"
574 #include "clutter-animatable.h"
575 #include "clutter-color-static.h"
576 #include "clutter-color.h"
577 #include "clutter-constraint.h"
578 #include "clutter-container.h"
579 #include "clutter-content-private.h"
580 #include "clutter-debug.h"
581 #include "clutter-effect-private.h"
582 #include "clutter-enum-types.h"
583 #include "clutter-fixed-layout.h"
584 #include "clutter-flatten-effect.h"
585 #include "clutter-interval.h"
586 #include "clutter-main.h"
587 #include "clutter-marshal.h"
588 #include "clutter-paint-nodes.h"
589 #include "clutter-paint-node-private.h"
590 #include "clutter-paint-volume-private.h"
591 #include "clutter-private.h"
592 #include "clutter-profile.h"
593 #include "clutter-property-transition.h"
594 #include "clutter-scriptable.h"
595 #include "clutter-script-private.h"
596 #include "clutter-stage-private.h"
597 #include "clutter-timeline.h"
598 #include "clutter-transition.h"
599 #include "clutter-units.h"
600
601 #include "deprecated/clutter-actor.h"
602 #include "deprecated/clutter-behaviour.h"
603 #include "deprecated/clutter-container.h"
604
605 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
606 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
607
608 /* Internal enum used to control mapped state update.  This is a hint
609  * which indicates when to do something other than just enforce
610  * invariants.
611  */
612 typedef enum {
613   MAP_STATE_CHECK,           /* just enforce invariants. */
614   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
615                               * used when about to unparent.
616                               */
617   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
618                               * used to set mapped on toplevels.
619                               */
620   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
621                               * used just before unmapping parent.
622                               */
623 } MapStateChange;
624
625 /* 3 entries should be a good compromise, few layout managers
626  * will ask for 3 different preferred size in each allocation cycle */
627 #define N_CACHED_SIZE_REQUESTS 3
628
629 struct _ClutterActorPrivate
630 {
631   /* request mode */
632   ClutterRequestMode request_mode;
633
634   /* our cached size requests for different width / height */
635   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
636   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
637
638   /* An age of 0 means the entry is not set */
639   guint cached_height_age;
640   guint cached_width_age;
641
642   /* the bounding box of the actor, relative to the parent's
643    * allocation
644    */
645   ClutterActorBox allocation;
646   ClutterAllocationFlags allocation_flags;
647
648   /* clip, in actor coordinates */
649   cairo_rectangle_t clip;
650
651   /* the cached transformation matrix; see apply_transform() */
652   CoglMatrix transform;
653
654   guint8 opacity;
655   gint opacity_override;
656
657   ClutterOffscreenRedirect offscreen_redirect;
658
659   /* This is an internal effect used to implement the
660      offscreen-redirect property */
661   ClutterEffect *flatten_effect;
662
663   /* scene graph */
664   ClutterActor *parent;
665   ClutterActor *prev_sibling;
666   ClutterActor *next_sibling;
667   ClutterActor *first_child;
668   ClutterActor *last_child;
669
670   gint n_children;
671
672   /* tracks whenever the children of an actor are changed; the
673    * age is incremented by 1 whenever an actor is added or
674    * removed. the age is not incremented when the first or the
675    * last child pointers are changed, or when grandchildren of
676    * an actor are changed.
677    */
678   gint age;
679
680   gchar *name; /* a non-unique name, used for debugging */
681   guint32 id; /* unique id, used for backward compatibility */
682
683   gint32 pick_id; /* per-stage unique id, used for picking */
684
685   /* a back-pointer to the Pango context that we can use
686    * to create pre-configured PangoLayout
687    */
688   PangoContext *pango_context;
689
690   /* the text direction configured for this child - either by
691    * application code, or by the actor's parent
692    */
693   ClutterTextDirection text_direction;
694
695   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
696   gint internal_child;
697
698   /* meta classes */
699   ClutterMetaGroup *actions;
700   ClutterMetaGroup *constraints;
701   ClutterMetaGroup *effects;
702
703   /* delegate object used to allocate the children of this actor */
704   ClutterLayoutManager *layout_manager;
705
706   /* delegate object used to paint the contents of this actor */
707   ClutterContent *content;
708
709   ClutterActorBox content_box;
710   ClutterContentGravity content_gravity;
711   ClutterScalingFilter min_filter;
712   ClutterScalingFilter mag_filter;
713
714   /* used when painting, to update the paint volume */
715   ClutterEffect *current_effect;
716
717   /* This is used to store an effect which needs to be redrawn. A
718      redraw can be queued to start from a particular effect. This is
719      used by parametrised effects that can cache an image of the
720      actor. If a parameter of the effect changes then it only needs to
721      redraw the cached image, not the actual actor. The pointer is
722      only valid if is_dirty == TRUE. If the pointer is NULL then the
723      whole actor is dirty. */
724   ClutterEffect *effect_to_redraw;
725
726   /* This is used when painting effects to implement the
727      clutter_actor_continue_paint() function. It points to the node in
728      the list of effects that is next in the chain */
729   const GList *next_effect_to_paint;
730
731   ClutterPaintVolume paint_volume;
732
733   /* NB: This volume isn't relative to this actor, it is in eye
734    * coordinates so that it can remain valid after the actor changes.
735    */
736   ClutterPaintVolume last_paint_volume;
737
738   ClutterStageQueueRedrawEntry *queue_redraw_entry;
739
740   ClutterColor bg_color;
741
742   /* bitfields */
743
744   /* fixed position and sizes */
745   guint position_set                : 1;
746   guint min_width_set               : 1;
747   guint min_height_set              : 1;
748   guint natural_width_set           : 1;
749   guint natural_height_set          : 1;
750   /* cached request is invalid (implies allocation is too) */
751   guint needs_width_request         : 1;
752   /* cached request is invalid (implies allocation is too) */
753   guint needs_height_request        : 1;
754   /* cached allocation is invalid (request has changed, probably) */
755   guint needs_allocation            : 1;
756   guint show_on_set_parent          : 1;
757   guint has_clip                    : 1;
758   guint clip_to_allocation          : 1;
759   guint enable_model_view_transform : 1;
760   guint enable_paint_unmapped       : 1;
761   guint has_pointer                 : 1;
762   guint propagated_one_redraw       : 1;
763   guint paint_volume_valid          : 1;
764   guint last_paint_volume_valid     : 1;
765   guint in_clone_paint              : 1;
766   guint transform_valid             : 1;
767   /* This is TRUE if anything has queued a redraw since we were last
768      painted. In this case effect_to_redraw will point to an effect
769      the redraw was queued from or it will be NULL if the redraw was
770      queued without an effect. */
771   guint is_dirty                    : 1;
772   guint bg_color_set                : 1;
773   guint content_box_valid           : 1;
774   guint x_expand_set                : 1;
775   guint y_expand_set                : 1;
776   guint needs_compute_expand        : 1;
777   guint needs_x_expand              : 1;
778   guint needs_y_expand              : 1;
779 };
780
781 enum
782 {
783   PROP_0,
784
785   PROP_NAME,
786
787   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
788    * when set they force a size request, when gotten they
789    * get the allocation if the allocation is valid, and the
790    * request otherwise
791    */
792   PROP_X,
793   PROP_Y,
794   PROP_WIDTH,
795   PROP_HEIGHT,
796
797   PROP_POSITION,
798   PROP_SIZE,
799
800   /* Then the rest of these size-related properties are the "actual"
801    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
802    */
803   PROP_FIXED_X,
804   PROP_FIXED_Y,
805
806   PROP_FIXED_POSITION_SET,
807
808   PROP_MIN_WIDTH,
809   PROP_MIN_WIDTH_SET,
810
811   PROP_MIN_HEIGHT,
812   PROP_MIN_HEIGHT_SET,
813
814   PROP_NATURAL_WIDTH,
815   PROP_NATURAL_WIDTH_SET,
816
817   PROP_NATURAL_HEIGHT,
818   PROP_NATURAL_HEIGHT_SET,
819
820   PROP_REQUEST_MODE,
821
822   /* Allocation properties are read-only */
823   PROP_ALLOCATION,
824
825   PROP_DEPTH,
826
827   PROP_CLIP,
828   PROP_HAS_CLIP,
829   PROP_CLIP_TO_ALLOCATION,
830
831   PROP_OPACITY,
832
833   PROP_OFFSCREEN_REDIRECT,
834
835   PROP_VISIBLE,
836   PROP_MAPPED,
837   PROP_REALIZED,
838   PROP_REACTIVE,
839
840   PROP_SCALE_X,
841   PROP_SCALE_Y,
842   PROP_SCALE_CENTER_X,
843   PROP_SCALE_CENTER_Y,
844   PROP_SCALE_GRAVITY,
845
846   PROP_ROTATION_ANGLE_X,
847   PROP_ROTATION_ANGLE_Y,
848   PROP_ROTATION_ANGLE_Z,
849   PROP_ROTATION_CENTER_X,
850   PROP_ROTATION_CENTER_Y,
851   PROP_ROTATION_CENTER_Z,
852   /* This property only makes sense for the z rotation because the
853      others would depend on the actor having a size along the
854      z-axis */
855   PROP_ROTATION_CENTER_Z_GRAVITY,
856
857   PROP_ANCHOR_X,
858   PROP_ANCHOR_Y,
859   PROP_ANCHOR_GRAVITY,
860
861   PROP_SHOW_ON_SET_PARENT,
862
863   PROP_TEXT_DIRECTION,
864   PROP_HAS_POINTER,
865
866   PROP_ACTIONS,
867   PROP_CONSTRAINTS,
868   PROP_EFFECT,
869
870   PROP_LAYOUT_MANAGER,
871
872   PROP_X_EXPAND,
873   PROP_Y_EXPAND,
874   PROP_X_ALIGN,
875   PROP_Y_ALIGN,
876   PROP_MARGIN_TOP,
877   PROP_MARGIN_BOTTOM,
878   PROP_MARGIN_LEFT,
879   PROP_MARGIN_RIGHT,
880
881   PROP_BACKGROUND_COLOR,
882   PROP_BACKGROUND_COLOR_SET,
883
884   PROP_FIRST_CHILD,
885   PROP_LAST_CHILD,
886
887   PROP_CONTENT,
888   PROP_CONTENT_GRAVITY,
889   PROP_CONTENT_BOX,
890   PROP_MINIFICATION_FILTER,
891   PROP_MAGNIFICATION_FILTER,
892
893   PROP_LAST
894 };
895
896 static GParamSpec *obj_props[PROP_LAST];
897
898 enum
899 {
900   SHOW,
901   HIDE,
902   DESTROY,
903   PARENT_SET,
904   KEY_FOCUS_IN,
905   KEY_FOCUS_OUT,
906   PAINT,
907   PICK,
908   REALIZE,
909   UNREALIZE,
910   QUEUE_REDRAW,
911   QUEUE_RELAYOUT,
912   EVENT,
913   CAPTURED_EVENT,
914   BUTTON_PRESS_EVENT,
915   BUTTON_RELEASE_EVENT,
916   SCROLL_EVENT,
917   KEY_PRESS_EVENT,
918   KEY_RELEASE_EVENT,
919   MOTION_EVENT,
920   ENTER_EVENT,
921   LEAVE_EVENT,
922   ALLOCATION_CHANGED,
923   TRANSITIONS_COMPLETED,
924
925   LAST_SIGNAL
926 };
927
928 static guint actor_signals[LAST_SIGNAL] = { 0, };
929
930 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
931 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
932 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
933 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
934
935 /* These setters are all static for now, maybe they should be in the
936  * public API, but they are perhaps obscure enough to leave only as
937  * properties
938  */
939 static void clutter_actor_set_min_width          (ClutterActor *self,
940                                                   gfloat        min_width);
941 static void clutter_actor_set_min_height         (ClutterActor *self,
942                                                   gfloat        min_height);
943 static void clutter_actor_set_natural_width      (ClutterActor *self,
944                                                   gfloat        natural_width);
945 static void clutter_actor_set_natural_height     (ClutterActor *self,
946                                                   gfloat        natural_height);
947 static void clutter_actor_set_min_width_set      (ClutterActor *self,
948                                                   gboolean      use_min_width);
949 static void clutter_actor_set_min_height_set     (ClutterActor *self,
950                                                   gboolean      use_min_height);
951 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
952                                                   gboolean  use_natural_width);
953 static void clutter_actor_set_natural_height_set (ClutterActor *self,
954                                                   gboolean  use_natural_height);
955 static void clutter_actor_update_map_state       (ClutterActor  *self,
956                                                   MapStateChange change);
957 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
958
959 /* Helper routines for managing anchor coords */
960 static void clutter_anchor_coord_get_units (ClutterActor      *self,
961                                             const AnchorCoord *coord,
962                                             gfloat            *x,
963                                             gfloat            *y,
964                                             gfloat            *z);
965 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
966                                             gfloat             x,
967                                             gfloat             y,
968                                             gfloat             z);
969
970 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
971 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
972                                                         ClutterGravity     gravity);
973
974 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
975
976 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
977
978 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
979                                                                ClutterActor *ancestor,
980                                                                CoglMatrix *matrix);
981
982 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
983
984 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
985
986 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
987                                                                 const ClutterColor *color);
988
989 static void on_layout_manager_changed (ClutterLayoutManager *manager,
990                                        ClutterActor         *self);
991
992 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
993
994 /* Helper macro which translates by the anchor coord, applies the
995    given transformation and then translates back */
996 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
997   gfloat _tx, _ty, _tz;                                                \
998   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
999   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1000   { _transform; }                                                      \
1001   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1002
1003 static GQuark quark_shader_data = 0;
1004 static GQuark quark_actor_layout_info = 0;
1005 static GQuark quark_actor_transform_info = 0;
1006 static GQuark quark_actor_animation_info = 0;
1007
1008 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1009                          clutter_actor,
1010                          G_TYPE_INITIALLY_UNOWNED,
1011                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1012                                                 clutter_container_iface_init)
1013                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1014                                                 clutter_scriptable_iface_init)
1015                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1016                                                 clutter_animatable_iface_init)
1017                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1018                                                 atk_implementor_iface_init));
1019
1020 /*< private >
1021  * clutter_actor_get_debug_name:
1022  * @actor: a #ClutterActor
1023  *
1024  * Retrieves a printable name of @actor for debugging messages
1025  *
1026  * Return value: a string with a printable name
1027  */
1028 const gchar *
1029 _clutter_actor_get_debug_name (ClutterActor *actor)
1030 {
1031   return actor->priv->name != NULL ? actor->priv->name
1032                                    : G_OBJECT_TYPE_NAME (actor);
1033 }
1034
1035 #ifdef CLUTTER_ENABLE_DEBUG
1036 /* XXX - this is for debugging only, remove once working (or leave
1037  * in only in some debug mode). Should leave it for a little while
1038  * until we're confident in the new map/realize/visible handling.
1039  */
1040 static inline void
1041 clutter_actor_verify_map_state (ClutterActor *self)
1042 {
1043   ClutterActorPrivate *priv = self->priv;
1044
1045   if (CLUTTER_ACTOR_IS_REALIZED (self))
1046     {
1047       /* all bets are off during reparent when we're potentially realized,
1048        * but should not be according to invariants
1049        */
1050       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1051         {
1052           if (priv->parent == NULL)
1053             {
1054               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1055                 {
1056                 }
1057               else
1058                 g_warning ("Realized non-toplevel actor '%s' should "
1059                            "have a parent",
1060                            _clutter_actor_get_debug_name (self));
1061             }
1062           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1063             {
1064               g_warning ("Realized actor %s has an unrealized parent %s",
1065                          _clutter_actor_get_debug_name (self),
1066                          _clutter_actor_get_debug_name (priv->parent));
1067             }
1068         }
1069     }
1070
1071   if (CLUTTER_ACTOR_IS_MAPPED (self))
1072     {
1073       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1074         g_warning ("Actor '%s' is mapped but not realized",
1075                    _clutter_actor_get_debug_name (self));
1076
1077       /* remaining bets are off during reparent when we're potentially
1078        * mapped, but should not be according to invariants
1079        */
1080       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1081         {
1082           if (priv->parent == NULL)
1083             {
1084               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1085                 {
1086                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1087                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1088                     {
1089                       g_warning ("Toplevel actor '%s' is mapped "
1090                                  "but not visible",
1091                                  _clutter_actor_get_debug_name (self));
1092                     }
1093                 }
1094               else
1095                 {
1096                   g_warning ("Mapped actor '%s' should have a parent",
1097                              _clutter_actor_get_debug_name (self));
1098                 }
1099             }
1100           else
1101             {
1102               ClutterActor *iter = self;
1103
1104               /* check for the enable_paint_unmapped flag on the actor
1105                * and parents; if the flag is enabled at any point of this
1106                * branch of the scene graph then all the later checks
1107                * become pointless
1108                */
1109               while (iter != NULL)
1110                 {
1111                   if (iter->priv->enable_paint_unmapped)
1112                     return;
1113
1114                   iter = iter->priv->parent;
1115                 }
1116
1117               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1118                 {
1119                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1120                              "is not visible",
1121                              _clutter_actor_get_debug_name (self),
1122                              _clutter_actor_get_debug_name (priv->parent));
1123                 }
1124
1125               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1126                 {
1127                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1128                              "is not realized",
1129                              _clutter_actor_get_debug_name (self),
1130                              _clutter_actor_get_debug_name (priv->parent));
1131                 }
1132
1133               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1134                 {
1135                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1136                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1137                                "parent '%s' is not mapped",
1138                                _clutter_actor_get_debug_name (self),
1139                                _clutter_actor_get_debug_name (priv->parent));
1140                 }
1141             }
1142         }
1143     }
1144 }
1145
1146 #endif /* CLUTTER_ENABLE_DEBUG */
1147
1148 static void
1149 clutter_actor_set_mapped (ClutterActor *self,
1150                           gboolean      mapped)
1151 {
1152   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1153     return;
1154
1155   if (mapped)
1156     {
1157       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1158       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1159     }
1160   else
1161     {
1162       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1163       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1164     }
1165 }
1166
1167 /* this function updates the mapped and realized states according to
1168  * invariants, in the appropriate order.
1169  */
1170 static void
1171 clutter_actor_update_map_state (ClutterActor  *self,
1172                                 MapStateChange change)
1173 {
1174   gboolean was_mapped;
1175
1176   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1177
1178   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1179     {
1180       /* the mapped flag on top-level actors must be set by the
1181        * per-backend implementation because it might be asynchronous.
1182        *
1183        * That is, the MAPPED flag on toplevels currently tracks the X
1184        * server mapped-ness of the window, while the expected behavior
1185        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1186        * This creates some weird complexity by breaking the invariant
1187        * that if we're visible and all ancestors shown then we are
1188        * also mapped - instead, we are mapped if all ancestors
1189        * _possibly excepting_ the stage are mapped. The stage
1190        * will map/unmap for example when it is minimized or
1191        * moved to another workspace.
1192        *
1193        * So, the only invariant on the stage is that if visible it
1194        * should be realized, and that it has to be visible to be
1195        * mapped.
1196        */
1197       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1198         clutter_actor_realize (self);
1199
1200       switch (change)
1201         {
1202         case MAP_STATE_CHECK:
1203           break;
1204
1205         case MAP_STATE_MAKE_MAPPED:
1206           g_assert (!was_mapped);
1207           clutter_actor_set_mapped (self, TRUE);
1208           break;
1209
1210         case MAP_STATE_MAKE_UNMAPPED:
1211           g_assert (was_mapped);
1212           clutter_actor_set_mapped (self, FALSE);
1213           break;
1214
1215         case MAP_STATE_MAKE_UNREALIZED:
1216           /* we only use MAKE_UNREALIZED in unparent,
1217            * and unparenting a stage isn't possible.
1218            * If someone wants to just unrealize a stage
1219            * then clutter_actor_unrealize() doesn't
1220            * go through this codepath.
1221            */
1222           g_warning ("Trying to force unrealize stage is not allowed");
1223           break;
1224         }
1225
1226       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1227           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1228           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1229         {
1230           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1231                      "it is somehow still mapped",
1232                      _clutter_actor_get_debug_name (self));
1233         }
1234     }
1235   else
1236     {
1237       ClutterActorPrivate *priv = self->priv;
1238       ClutterActor *parent = priv->parent;
1239       gboolean should_be_mapped;
1240       gboolean may_be_realized;
1241       gboolean must_be_realized;
1242
1243       should_be_mapped = FALSE;
1244       may_be_realized = TRUE;
1245       must_be_realized = FALSE;
1246
1247       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1248         {
1249           may_be_realized = FALSE;
1250         }
1251       else
1252         {
1253           /* Maintain invariant that if parent is mapped, and we are
1254            * visible, then we are mapped ...  unless parent is a
1255            * stage, in which case we map regardless of parent's map
1256            * state but do require stage to be visible and realized.
1257            *
1258            * If parent is realized, that does not force us to be
1259            * realized; but if parent is unrealized, that does force
1260            * us to be unrealized.
1261            *
1262            * The reason we don't force children to realize with
1263            * parents is _clutter_actor_rerealize(); if we require that
1264            * a realized parent means children are realized, then to
1265            * unrealize an actor we would have to unrealize its
1266            * parents, which would end up meaning unrealizing and
1267            * hiding the entire stage. So we allow unrealizing a
1268            * child (as long as that child is not mapped) while that
1269            * child still has a realized parent.
1270            *
1271            * Also, if we unrealize from leaf nodes to root, and
1272            * realize from root to leaf, the invariants are never
1273            * violated if we allow children to be unrealized
1274            * while parents are realized.
1275            *
1276            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1277            * to force us to unmap, even though parent is still
1278            * mapped. This is because we're unmapping from leaf nodes
1279            * up to root nodes.
1280            */
1281           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1282               change != MAP_STATE_MAKE_UNMAPPED)
1283             {
1284               gboolean parent_is_visible_realized_toplevel;
1285
1286               parent_is_visible_realized_toplevel =
1287                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1288                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1289                  CLUTTER_ACTOR_IS_REALIZED (parent));
1290
1291               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1292                   parent_is_visible_realized_toplevel)
1293                 {
1294                   must_be_realized = TRUE;
1295                   should_be_mapped = TRUE;
1296                 }
1297             }
1298
1299           /* if the actor has been set to be painted even if unmapped
1300            * then we should map it and check for realization as well;
1301            * this is an override for the branch of the scene graph
1302            * which begins with this node
1303            */
1304           if (priv->enable_paint_unmapped)
1305             {
1306               if (priv->parent == NULL)
1307                 g_warning ("Attempting to map an unparented actor '%s'",
1308                            _clutter_actor_get_debug_name (self));
1309
1310               should_be_mapped = TRUE;
1311               must_be_realized = TRUE;
1312             }
1313
1314           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1315             may_be_realized = FALSE;
1316         }
1317
1318       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1319         {
1320           if (parent == NULL)
1321             g_warning ("Attempting to map a child that does not "
1322                        "meet the necessary invariants: the actor '%s' "
1323                        "has no parent",
1324                        _clutter_actor_get_debug_name (self));
1325           else
1326             g_warning ("Attempting to map a child that does not "
1327                        "meet the necessary invariants: the actor '%s' "
1328                        "is parented to an unmapped actor '%s'",
1329                        _clutter_actor_get_debug_name (self),
1330                        _clutter_actor_get_debug_name (priv->parent));
1331         }
1332
1333       /* If in reparent, we temporarily suspend unmap and unrealize.
1334        *
1335        * We want to go in the order "realize, map" and "unmap, unrealize"
1336        */
1337
1338       /* Unmap */
1339       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1340         clutter_actor_set_mapped (self, FALSE);
1341
1342       /* Realize */
1343       if (must_be_realized)
1344         clutter_actor_realize (self);
1345
1346       /* if we must be realized then we may be, presumably */
1347       g_assert (!(must_be_realized && !may_be_realized));
1348
1349       /* Unrealize */
1350       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1351         clutter_actor_unrealize_not_hiding (self);
1352
1353       /* Map */
1354       if (should_be_mapped)
1355         {
1356           if (!must_be_realized)
1357             g_warning ("Somehow we think actor '%s' should be mapped but "
1358                        "not realized, which isn't allowed",
1359                        _clutter_actor_get_debug_name (self));
1360
1361           /* realization is allowed to fail (though I don't know what
1362            * an app is supposed to do about that - shouldn't it just
1363            * be a g_error? anyway, we have to avoid mapping if this
1364            * happens)
1365            */
1366           if (CLUTTER_ACTOR_IS_REALIZED (self))
1367             clutter_actor_set_mapped (self, TRUE);
1368         }
1369     }
1370
1371 #ifdef CLUTTER_ENABLE_DEBUG
1372   /* check all invariants were kept */
1373   clutter_actor_verify_map_state (self);
1374 #endif
1375 }
1376
1377 static void
1378 clutter_actor_real_map (ClutterActor *self)
1379 {
1380   ClutterActorPrivate *priv = self->priv;
1381   ClutterActor *stage, *iter;
1382
1383   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1384
1385   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1386                 _clutter_actor_get_debug_name (self));
1387
1388   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1389
1390   stage = _clutter_actor_get_stage_internal (self);
1391   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1392
1393   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1394                 priv->pick_id,
1395                 _clutter_actor_get_debug_name (self));
1396
1397   /* notify on parent mapped before potentially mapping
1398    * children, so apps see a top-down notification.
1399    */
1400   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1401
1402   for (iter = self->priv->first_child;
1403        iter != NULL;
1404        iter = iter->priv->next_sibling)
1405     {
1406       clutter_actor_map (iter);
1407     }
1408 }
1409
1410 /**
1411  * clutter_actor_map:
1412  * @self: A #ClutterActor
1413  *
1414  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1415  * and realizes its children if they are visible. Does nothing if the
1416  * actor is not visible.
1417  *
1418  * Calling this function is strongly disencouraged: the default
1419  * implementation of #ClutterActorClass.map() will map all the children
1420  * of an actor when mapping its parent.
1421  *
1422  * When overriding map, it is mandatory to chain up to the parent
1423  * implementation.
1424  *
1425  * Since: 1.0
1426  */
1427 void
1428 clutter_actor_map (ClutterActor *self)
1429 {
1430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1431
1432   if (CLUTTER_ACTOR_IS_MAPPED (self))
1433     return;
1434
1435   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1436     return;
1437
1438   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1439 }
1440
1441 static void
1442 clutter_actor_real_unmap (ClutterActor *self)
1443 {
1444   ClutterActorPrivate *priv = self->priv;
1445   ClutterActor *iter;
1446
1447   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1448
1449   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1450                 _clutter_actor_get_debug_name (self));
1451
1452   for (iter = self->priv->first_child;
1453        iter != NULL;
1454        iter = iter->priv->next_sibling)
1455     {
1456       clutter_actor_unmap (iter);
1457     }
1458
1459   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1460
1461   /* clear the contents of the last paint volume, so that hiding + moving +
1462    * showing will not result in the wrong area being repainted
1463    */
1464   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1465   priv->last_paint_volume_valid = TRUE;
1466
1467   /* notify on parent mapped after potentially unmapping
1468    * children, so apps see a bottom-up notification.
1469    */
1470   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1471
1472   /* relinquish keyboard focus if we were unmapped while owning it */
1473   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1474     {
1475       ClutterStage *stage;
1476
1477       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1478
1479       if (stage != NULL)
1480         _clutter_stage_release_pick_id (stage, priv->pick_id);
1481
1482       priv->pick_id = -1;
1483
1484       if (stage != NULL &&
1485           clutter_stage_get_key_focus (stage) == self)
1486         {
1487           clutter_stage_set_key_focus (stage, NULL);
1488         }
1489     }
1490 }
1491
1492 /**
1493  * clutter_actor_unmap:
1494  * @self: A #ClutterActor
1495  *
1496  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1497  * unmaps its children if they were mapped.
1498  *
1499  * Calling this function is not encouraged: the default #ClutterActor
1500  * implementation of #ClutterActorClass.unmap() will also unmap any
1501  * eventual children by default when their parent is unmapped.
1502  *
1503  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1504  * chain up to the parent implementation.
1505  *
1506  * <note>It is important to note that the implementation of the
1507  * #ClutterActorClass.unmap() virtual function may be called after
1508  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1509  * implementation, but it is guaranteed to be called before the
1510  * #GObjectClass.finalize() implementation.</note>
1511  *
1512  * Since: 1.0
1513  */
1514 void
1515 clutter_actor_unmap (ClutterActor *self)
1516 {
1517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1518
1519   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1520     return;
1521
1522   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1523 }
1524
1525 static void
1526 clutter_actor_real_show (ClutterActor *self)
1527 {
1528   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1529     {
1530       ClutterActorPrivate *priv = self->priv;
1531
1532       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1533
1534       /* we notify on the "visible" flag in the clutter_actor_show()
1535        * wrapper so the entire show signal emission completes first
1536        * (?)
1537        */
1538       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539
1540       /* we queue a relayout unless the actor is inside a
1541        * container that explicitly told us not to
1542        */
1543       if (priv->parent != NULL &&
1544           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1545         {
1546           /* While an actor is hidden the parent may not have
1547            * allocated/requested so we need to start from scratch
1548            * and avoid the short-circuiting in
1549            * clutter_actor_queue_relayout().
1550            */
1551           priv->needs_width_request  = FALSE;
1552           priv->needs_height_request = FALSE;
1553           priv->needs_allocation     = FALSE;
1554           clutter_actor_queue_relayout (self);
1555         }
1556     }
1557 }
1558
1559 static inline void
1560 set_show_on_set_parent (ClutterActor *self,
1561                         gboolean      set_show)
1562 {
1563   ClutterActorPrivate *priv = self->priv;
1564
1565   set_show = !!set_show;
1566
1567   if (priv->show_on_set_parent == set_show)
1568     return;
1569
1570   if (priv->parent == NULL)
1571     {
1572       priv->show_on_set_parent = set_show;
1573       g_object_notify_by_pspec (G_OBJECT (self),
1574                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1575     }
1576 }
1577
1578 /**
1579  * clutter_actor_show:
1580  * @self: A #ClutterActor
1581  *
1582  * Flags an actor to be displayed. An actor that isn't shown will not
1583  * be rendered on the stage.
1584  *
1585  * Actors are visible by default.
1586  *
1587  * If this function is called on an actor without a parent, the
1588  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1589  * effect.
1590  */
1591 void
1592 clutter_actor_show (ClutterActor *self)
1593 {
1594   ClutterActorPrivate *priv;
1595
1596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1597
1598   /* simple optimization */
1599   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1600     {
1601       /* we still need to set the :show-on-set-parent property, in
1602        * case show() is called on an unparented actor
1603        */
1604       set_show_on_set_parent (self, TRUE);
1605       return;
1606     }
1607
1608 #ifdef CLUTTER_ENABLE_DEBUG
1609   clutter_actor_verify_map_state (self);
1610 #endif
1611
1612   priv = self->priv;
1613
1614   g_object_freeze_notify (G_OBJECT (self));
1615
1616   set_show_on_set_parent (self, TRUE);
1617
1618   /* if we're showing a child that needs to expand, or may
1619    * expand, then we need to recompute the expand flags for
1620    * its parent as well
1621    */
1622   if (priv->needs_compute_expand ||
1623       priv->needs_x_expand ||
1624       priv->needs_y_expand)
1625     {
1626       clutter_actor_queue_compute_expand (self);
1627     }
1628
1629   g_signal_emit (self, actor_signals[SHOW], 0);
1630   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1631
1632   if (priv->parent != NULL)
1633     clutter_actor_queue_redraw (priv->parent);
1634
1635   g_object_thaw_notify (G_OBJECT (self));
1636 }
1637
1638 /**
1639  * clutter_actor_show_all:
1640  * @self: a #ClutterActor
1641  *
1642  * Calls clutter_actor_show() on all children of an actor (if any).
1643  *
1644  * Since: 0.2
1645  *
1646  * Deprecated: 1.10: Actors are visible by default
1647  */
1648 void
1649 clutter_actor_show_all (ClutterActor *self)
1650 {
1651   ClutterActorClass *klass;
1652
1653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1654
1655   klass = CLUTTER_ACTOR_GET_CLASS (self);
1656   if (klass->show_all)
1657     klass->show_all (self);
1658 }
1659
1660 static void
1661 clutter_actor_real_hide (ClutterActor *self)
1662 {
1663   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1664     {
1665       ClutterActorPrivate *priv = self->priv;
1666
1667       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1668
1669       /* we notify on the "visible" flag in the clutter_actor_hide()
1670        * wrapper so the entire hide signal emission completes first
1671        * (?)
1672        */
1673       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1674
1675       /* we queue a relayout unless the actor is inside a
1676        * container that explicitly told us not to
1677        */
1678       if (priv->parent != NULL &&
1679           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1680         clutter_actor_queue_relayout (priv->parent);
1681     }
1682 }
1683
1684 /**
1685  * clutter_actor_hide:
1686  * @self: A #ClutterActor
1687  *
1688  * Flags an actor to be hidden. A hidden actor will not be
1689  * rendered on the stage.
1690  *
1691  * Actors are visible by default.
1692  *
1693  * If this function is called on an actor without a parent, the
1694  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1695  * as a side-effect.
1696  */
1697 void
1698 clutter_actor_hide (ClutterActor *self)
1699 {
1700   ClutterActorPrivate *priv;
1701
1702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1703
1704   /* simple optimization */
1705   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1706     {
1707       /* we still need to set the :show-on-set-parent property, in
1708        * case hide() is called on an unparented actor
1709        */
1710       set_show_on_set_parent (self, FALSE);
1711       return;
1712     }
1713
1714 #ifdef CLUTTER_ENABLE_DEBUG
1715   clutter_actor_verify_map_state (self);
1716 #endif
1717
1718   priv = self->priv;
1719
1720   g_object_freeze_notify (G_OBJECT (self));
1721
1722   set_show_on_set_parent (self, FALSE);
1723
1724   /* if we're hiding a child that needs to expand, or may
1725    * expand, then we need to recompute the expand flags for
1726    * its parent as well
1727    */
1728   if (priv->needs_compute_expand ||
1729       priv->needs_x_expand ||
1730       priv->needs_y_expand)
1731     {
1732       clutter_actor_queue_compute_expand (self);
1733     }
1734
1735   g_signal_emit (self, actor_signals[HIDE], 0);
1736   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1737
1738   if (priv->parent != NULL)
1739     clutter_actor_queue_redraw (priv->parent);
1740
1741   g_object_thaw_notify (G_OBJECT (self));
1742 }
1743
1744 /**
1745  * clutter_actor_hide_all:
1746  * @self: a #ClutterActor
1747  *
1748  * Calls clutter_actor_hide() on all child actors (if any).
1749  *
1750  * Since: 0.2
1751  *
1752  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1753  *   prevent its children from being painted as well.
1754  */
1755 void
1756 clutter_actor_hide_all (ClutterActor *self)
1757 {
1758   ClutterActorClass *klass;
1759
1760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1761
1762   klass = CLUTTER_ACTOR_GET_CLASS (self);
1763   if (klass->hide_all)
1764     klass->hide_all (self);
1765 }
1766
1767 /**
1768  * clutter_actor_realize:
1769  * @self: A #ClutterActor
1770  *
1771  * Realization informs the actor that it is attached to a stage. It
1772  * can use this to allocate resources if it wanted to delay allocation
1773  * until it would be rendered. However it is perfectly acceptable for
1774  * an actor to create resources before being realized because Clutter
1775  * only ever has a single rendering context so that actor is free to
1776  * be moved from one stage to another.
1777  *
1778  * This function does nothing if the actor is already realized.
1779  *
1780  * Because a realized actor must have realized parent actors, calling
1781  * clutter_actor_realize() will also realize all parents of the actor.
1782  *
1783  * This function does not realize child actors, except in the special
1784  * case that realizing the stage, when the stage is visible, will
1785  * suddenly map (and thus realize) the children of the stage.
1786  **/
1787 void
1788 clutter_actor_realize (ClutterActor *self)
1789 {
1790   ClutterActorPrivate *priv;
1791
1792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1793
1794   priv = self->priv;
1795
1796 #ifdef CLUTTER_ENABLE_DEBUG
1797   clutter_actor_verify_map_state (self);
1798 #endif
1799
1800   if (CLUTTER_ACTOR_IS_REALIZED (self))
1801     return;
1802
1803   /* To be realized, our parent actors must be realized first.
1804    * This will only succeed if we're inside a toplevel.
1805    */
1806   if (priv->parent != NULL)
1807     clutter_actor_realize (priv->parent);
1808
1809   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1810     {
1811       /* toplevels can be realized at any time */
1812     }
1813   else
1814     {
1815       /* "Fail" the realization if parent is missing or unrealized;
1816        * this should really be a g_warning() not some kind of runtime
1817        * failure; how can an app possibly recover? Instead it's a bug
1818        * in the app and the app should get an explanatory warning so
1819        * someone can fix it. But for now it's too hard to fix this
1820        * because e.g. ClutterTexture needs reworking.
1821        */
1822       if (priv->parent == NULL ||
1823           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1824         return;
1825     }
1826
1827   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1828
1829   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1830   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1831
1832   g_signal_emit (self, actor_signals[REALIZE], 0);
1833
1834   /* Stage actor is allowed to unset the realized flag again in its
1835    * default signal handler, though that is a pathological situation.
1836    */
1837
1838   /* If realization "failed" we'll have to update child state. */
1839   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1840 }
1841
1842 static void
1843 clutter_actor_real_unrealize (ClutterActor *self)
1844 {
1845   /* we must be unmapped (implying our children are also unmapped) */
1846   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1847 }
1848
1849 /**
1850  * clutter_actor_unrealize:
1851  * @self: A #ClutterActor
1852  *
1853  * Unrealization informs the actor that it may be being destroyed or
1854  * moved to another stage. The actor may want to destroy any
1855  * underlying graphics resources at this point. However it is
1856  * perfectly acceptable for it to retain the resources until the actor
1857  * is destroyed because Clutter only ever uses a single rendering
1858  * context and all of the graphics resources are valid on any stage.
1859  *
1860  * Because mapped actors must be realized, actors may not be
1861  * unrealized if they are mapped. This function hides the actor to be
1862  * sure it isn't mapped, an application-visible side effect that you
1863  * may not be expecting.
1864  *
1865  * This function should not be called by application code.
1866  */
1867 void
1868 clutter_actor_unrealize (ClutterActor *self)
1869 {
1870   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1871   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1872
1873 /* This function should not really be in the public API, because
1874  * there isn't a good reason to call it. ClutterActor will already
1875  * unrealize things for you when it's important to do so.
1876  *
1877  * If you were using clutter_actor_unrealize() in a dispose
1878  * implementation, then don't, just chain up to ClutterActor's
1879  * dispose.
1880  *
1881  * If you were using clutter_actor_unrealize() to implement
1882  * unrealizing children of your container, then don't, ClutterActor
1883  * will already take care of that.
1884  *
1885  * If you were using clutter_actor_unrealize() to re-realize to
1886  * create your resources in a different way, then use
1887  * _clutter_actor_rerealize() (inside Clutter) or just call your
1888  * code that recreates your resources directly (outside Clutter).
1889  */
1890
1891 #ifdef CLUTTER_ENABLE_DEBUG
1892   clutter_actor_verify_map_state (self);
1893 #endif
1894
1895   clutter_actor_hide (self);
1896
1897   clutter_actor_unrealize_not_hiding (self);
1898 }
1899
1900 static ClutterActorTraverseVisitFlags
1901 unrealize_actor_before_children_cb (ClutterActor *self,
1902                                     int depth,
1903                                     void *user_data)
1904 {
1905   /* If an actor is already unrealized we know its children have also
1906    * already been unrealized... */
1907   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1908     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1909
1910   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1911
1912   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1913 }
1914
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_after_children_cb (ClutterActor *self,
1917                                    int depth,
1918                                    void *user_data)
1919 {
1920   /* We want to unset the realized flag only _after_
1921    * child actors are unrealized, to maintain invariants.
1922    */
1923   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1924   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1925   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1926 }
1927
1928 /*
1929  * clutter_actor_unrealize_not_hiding:
1930  * @self: A #ClutterActor
1931  *
1932  * Unrealization informs the actor that it may be being destroyed or
1933  * moved to another stage. The actor may want to destroy any
1934  * underlying graphics resources at this point. However it is
1935  * perfectly acceptable for it to retain the resources until the actor
1936  * is destroyed because Clutter only ever uses a single rendering
1937  * context and all of the graphics resources are valid on any stage.
1938  *
1939  * Because mapped actors must be realized, actors may not be
1940  * unrealized if they are mapped. You must hide the actor or one of
1941  * its parents before attempting to unrealize.
1942  *
1943  * This function is separate from clutter_actor_unrealize() because it
1944  * does not automatically hide the actor.
1945  * Actors need not be hidden to be unrealized, they just need to
1946  * be unmapped. In fact we don't want to mess up the application's
1947  * setting of the "visible" flag, so hiding is very undesirable.
1948  *
1949  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1950  * backward compatibility.
1951  */
1952 static void
1953 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1954 {
1955   _clutter_actor_traverse (self,
1956                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1957                            unrealize_actor_before_children_cb,
1958                            unrealize_actor_after_children_cb,
1959                            NULL);
1960 }
1961
1962 /*
1963  * _clutter_actor_rerealize:
1964  * @self: A #ClutterActor
1965  * @callback: Function to call while unrealized
1966  * @data: data for callback
1967  *
1968  * If an actor is already unrealized, this just calls the callback.
1969  *
1970  * If it is realized, it unrealizes temporarily, calls the callback,
1971  * and then re-realizes the actor.
1972  *
1973  * As a side effect, leaves all children of the actor unrealized if
1974  * the actor was realized but not showing.  This is because when we
1975  * unrealize the actor temporarily we must unrealize its children
1976  * (e.g. children of a stage can't be realized if stage window is
1977  * gone). And we aren't clever enough to save the realization state of
1978  * all children. In most cases this should not matter, because
1979  * the children will automatically realize when they next become mapped.
1980  */
1981 void
1982 _clutter_actor_rerealize (ClutterActor    *self,
1983                           ClutterCallback  callback,
1984                           void            *data)
1985 {
1986   gboolean was_mapped;
1987   gboolean was_showing;
1988   gboolean was_realized;
1989
1990   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1991
1992 #ifdef CLUTTER_ENABLE_DEBUG
1993   clutter_actor_verify_map_state (self);
1994 #endif
1995
1996   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1997   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1998   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1999
2000   /* Must be unmapped to unrealize. Note we only have to hide this
2001    * actor if it was mapped (if all parents were showing).  If actor
2002    * is merely visible (but not mapped), then that's fine, we can
2003    * leave it visible.
2004    */
2005   if (was_mapped)
2006     clutter_actor_hide (self);
2007
2008   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2009
2010   /* unrealize self and all children */
2011   clutter_actor_unrealize_not_hiding (self);
2012
2013   if (callback != NULL)
2014     {
2015       (* callback) (self, data);
2016     }
2017
2018   if (was_showing)
2019     clutter_actor_show (self); /* will realize only if mapping implies it */
2020   else if (was_realized)
2021     clutter_actor_realize (self); /* realize self and all parents */
2022 }
2023
2024 static void
2025 clutter_actor_real_pick (ClutterActor       *self,
2026                          const ClutterColor *color)
2027 {
2028   /* the default implementation is just to paint a rectangle
2029    * with the same size of the actor using the passed color
2030    */
2031   if (clutter_actor_should_pick_paint (self))
2032     {
2033       ClutterActorBox box = { 0, };
2034       float width, height;
2035
2036       clutter_actor_get_allocation_box (self, &box);
2037
2038       width = box.x2 - box.x1;
2039       height = box.y2 - box.y1;
2040
2041       cogl_set_source_color4ub (color->red,
2042                                 color->green,
2043                                 color->blue,
2044                                 color->alpha);
2045
2046       cogl_rectangle (0, 0, width, height);
2047     }
2048
2049   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2050    * with existing container classes that override the pick() virtual
2051    * and chain up to the default implementation - otherwise we'll end up
2052    * painting our children twice.
2053    *
2054    * this has to go away for 2.0; hopefully along the pick() itself.
2055    */
2056   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2057     {
2058       ClutterActor *iter;
2059
2060       for (iter = self->priv->first_child;
2061            iter != NULL;
2062            iter = iter->priv->next_sibling)
2063         clutter_actor_paint (iter);
2064     }
2065 }
2066
2067 /**
2068  * clutter_actor_should_pick_paint:
2069  * @self: A #ClutterActor
2070  *
2071  * Should be called inside the implementation of the
2072  * #ClutterActor::pick virtual function in order to check whether
2073  * the actor should paint itself in pick mode or not.
2074  *
2075  * This function should never be called directly by applications.
2076  *
2077  * Return value: %TRUE if the actor should paint its silhouette,
2078  *   %FALSE otherwise
2079  */
2080 gboolean
2081 clutter_actor_should_pick_paint (ClutterActor *self)
2082 {
2083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2084
2085   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2086       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2087        CLUTTER_ACTOR_IS_REACTIVE (self)))
2088     return TRUE;
2089
2090   return FALSE;
2091 }
2092
2093 static void
2094 clutter_actor_real_get_preferred_width (ClutterActor *self,
2095                                         gfloat        for_height,
2096                                         gfloat       *min_width_p,
2097                                         gfloat       *natural_width_p)
2098 {
2099   ClutterActorPrivate *priv = self->priv;
2100
2101   if (priv->n_children != 0 &&
2102       priv->layout_manager != NULL)
2103     {
2104       ClutterContainer *container = CLUTTER_CONTAINER (self);
2105
2106       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2107                     "for the preferred width",
2108                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2109                     priv->layout_manager);
2110
2111       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2112                                                   container,
2113                                                   for_height,
2114                                                   min_width_p,
2115                                                   natural_width_p);
2116
2117       return;
2118     }
2119
2120   /* Default implementation is always 0x0, usually an actor
2121    * using this default is relying on someone to set the
2122    * request manually
2123    */
2124   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2125
2126   if (min_width_p)
2127     *min_width_p = 0;
2128
2129   if (natural_width_p)
2130     *natural_width_p = 0;
2131 }
2132
2133 static void
2134 clutter_actor_real_get_preferred_height (ClutterActor *self,
2135                                          gfloat        for_width,
2136                                          gfloat       *min_height_p,
2137                                          gfloat       *natural_height_p)
2138 {
2139   ClutterActorPrivate *priv = self->priv;
2140
2141   if (priv->n_children != 0 &&
2142       priv->layout_manager != NULL)
2143     {
2144       ClutterContainer *container = CLUTTER_CONTAINER (self);
2145
2146       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2147                     "for the preferred height",
2148                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2149                     priv->layout_manager);
2150
2151       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2152                                                    container,
2153                                                    for_width,
2154                                                    min_height_p,
2155                                                    natural_height_p);
2156
2157       return;
2158     }
2159   /* Default implementation is always 0x0, usually an actor
2160    * using this default is relying on someone to set the
2161    * request manually
2162    */
2163   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2164
2165   if (min_height_p)
2166     *min_height_p = 0;
2167
2168   if (natural_height_p)
2169     *natural_height_p = 0;
2170 }
2171
2172 static void
2173 clutter_actor_store_old_geometry (ClutterActor    *self,
2174                                   ClutterActorBox *box)
2175 {
2176   *box = self->priv->allocation;
2177 }
2178
2179 static inline void
2180 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2181                                           const ClutterActorBox *old)
2182 {
2183   ClutterActorPrivate *priv = self->priv;
2184   GObject *obj = G_OBJECT (self);
2185
2186   g_object_freeze_notify (obj);
2187
2188   /* to avoid excessive requisition or allocation cycles we
2189    * use the cached values.
2190    *
2191    * - if we don't have an allocation we assume that we need
2192    *   to notify anyway
2193    * - if we don't have a width or a height request we notify
2194    *   width and height
2195    * - if we have a valid allocation then we check the old
2196    *   bounding box with the current allocation and we notify
2197    *   the changes
2198    */
2199   if (priv->needs_allocation)
2200     {
2201       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2202       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2203       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2204       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2205       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2206       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2207     }
2208   else if (priv->needs_width_request || priv->needs_height_request)
2209     {
2210       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2211       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2212       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2213     }
2214   else
2215     {
2216       gfloat x, y;
2217       gfloat width, height;
2218
2219       x = priv->allocation.x1;
2220       y = priv->allocation.y1;
2221       width = priv->allocation.x2 - priv->allocation.x1;
2222       height = priv->allocation.y2 - priv->allocation.y1;
2223
2224       if (x != old->x1)
2225         {
2226           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2227           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2228         }
2229
2230       if (y != old->y1)
2231         {
2232           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2233           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2234         }
2235
2236       if (width != (old->x2 - old->x1))
2237         {
2238           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2239           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2240         }
2241
2242       if (height != (old->y2 - old->y1))
2243         {
2244           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2245           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2246         }
2247     }
2248
2249   g_object_thaw_notify (obj);
2250 }
2251
2252 /*< private >
2253  * clutter_actor_set_allocation_internal:
2254  * @self: a #ClutterActor
2255  * @box: a #ClutterActorBox
2256  * @flags: allocation flags
2257  *
2258  * Stores the allocation of @self.
2259  *
2260  * This function only performs basic storage and property notification.
2261  *
2262  * This function should be called by clutter_actor_set_allocation()
2263  * and by the default implementation of #ClutterActorClass.allocate().
2264  *
2265  * Return value: %TRUE if the allocation of the #ClutterActor has been
2266  *   changed, and %FALSE otherwise
2267  */
2268 static inline gboolean
2269 clutter_actor_set_allocation_internal (ClutterActor           *self,
2270                                        const ClutterActorBox  *box,
2271                                        ClutterAllocationFlags  flags)
2272 {
2273   ClutterActorPrivate *priv = self->priv;
2274   GObject *obj;
2275   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2276   gboolean retval;
2277   ClutterActorBox old_alloc = { 0, };
2278
2279   obj = G_OBJECT (self);
2280
2281   g_object_freeze_notify (obj);
2282
2283   clutter_actor_store_old_geometry (self, &old_alloc);
2284
2285   x1_changed = priv->allocation.x1 != box->x1;
2286   y1_changed = priv->allocation.y1 != box->y1;
2287   x2_changed = priv->allocation.x2 != box->x2;
2288   y2_changed = priv->allocation.y2 != box->y2;
2289
2290   priv->allocation = *box;
2291   priv->allocation_flags = flags;
2292
2293   /* allocation is authoritative */
2294   priv->needs_width_request = FALSE;
2295   priv->needs_height_request = FALSE;
2296   priv->needs_allocation = FALSE;
2297
2298   if (x1_changed ||
2299       y1_changed ||
2300       x2_changed ||
2301       y2_changed)
2302     {
2303       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2304                     _clutter_actor_get_debug_name (self));
2305
2306       priv->transform_valid = FALSE;
2307
2308       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2309
2310       /* if the allocation changes, so does the content box */
2311       if (priv->content != NULL)
2312         {
2313           priv->content_box_valid = FALSE;
2314           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2315         }
2316
2317       retval = TRUE;
2318     }
2319   else
2320     retval = FALSE;
2321
2322   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2323
2324   g_object_thaw_notify (obj);
2325
2326   return retval;
2327 }
2328
2329 static void clutter_actor_real_allocate (ClutterActor           *self,
2330                                          const ClutterActorBox  *box,
2331                                          ClutterAllocationFlags  flags);
2332
2333 static inline void
2334 clutter_actor_maybe_layout_children (ClutterActor           *self,
2335                                      const ClutterActorBox  *allocation,
2336                                      ClutterAllocationFlags  flags)
2337 {
2338   ClutterActorPrivate *priv = self->priv;
2339
2340   /* this is going to be a bit hard to follow, so let's put an explanation
2341    * here.
2342    *
2343    * we want ClutterActor to have a default layout manager if the actor was
2344    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2345    *
2346    * we also want any subclass of ClutterActor that does not override the
2347    * ::allocate() virtual function to delegate to a layout manager.
2348    *
2349    * finally, we want to allow people subclassing ClutterActor and overriding
2350    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2351    *
2352    * on the other hand, we want existing actor subclasses overriding the
2353    * ::allocate() virtual function and chaining up to the parent's
2354    * implementation to continue working without allocating their children
2355    * twice, or without entering an allocation loop.
2356    *
2357    * for the first two points, we check if the class of the actor is
2358    * overridding the ::allocate() virtual function; if it isn't, then we
2359    * follow through with checking whether we have children and a layout
2360    * manager, and eventually calling clutter_layout_manager_allocate().
2361    *
2362    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2363    * allocation flags that we got passed, and if it is present, we continue
2364    * with the check above.
2365    *
2366    * if neither of these two checks yields a positive result, we just
2367    * assume that the ::allocate() virtual function that resulted in this
2368    * function being called will also allocate the children of the actor.
2369    */
2370
2371   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2372     goto check_layout;
2373
2374   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2375     goto check_layout;
2376
2377   return;
2378
2379 check_layout:
2380   if (priv->n_children != 0 &&
2381       priv->layout_manager != NULL)
2382     {
2383       ClutterContainer *container = CLUTTER_CONTAINER (self);
2384       ClutterAllocationFlags children_flags;
2385       ClutterActorBox children_box;
2386
2387       /* normalize the box passed to the layout manager */
2388       children_box.x1 = children_box.y1 = 0.f;
2389       children_box.x2 = (allocation->x2 - allocation->x1);
2390       children_box.y2 = (allocation->y2 - allocation->y1);
2391
2392       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2393        * the actor's children, since it refers only to the current
2394        * actor's allocation.
2395        */
2396       children_flags = flags;
2397       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2398
2399       CLUTTER_NOTE (LAYOUT,
2400                     "Allocating %d children of %s "
2401                     "at { %.2f, %.2f - %.2f x %.2f } "
2402                     "using %s",
2403                     priv->n_children,
2404                     _clutter_actor_get_debug_name (self),
2405                     allocation->x1,
2406                     allocation->y1,
2407                     (allocation->x2 - allocation->x1),
2408                     (allocation->y2 - allocation->y1),
2409                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2410
2411       clutter_layout_manager_allocate (priv->layout_manager,
2412                                        container,
2413                                        &children_box,
2414                                        children_flags);
2415     }
2416 }
2417
2418 static void
2419 clutter_actor_real_allocate (ClutterActor           *self,
2420                              const ClutterActorBox  *box,
2421                              ClutterAllocationFlags  flags)
2422 {
2423   ClutterActorPrivate *priv = self->priv;
2424   gboolean changed;
2425
2426   g_object_freeze_notify (G_OBJECT (self));
2427
2428   changed = clutter_actor_set_allocation_internal (self, box, flags);
2429
2430   /* we allocate our children before we notify changes in our geometry,
2431    * so that people connecting to properties will be able to get valid
2432    * data out of the sub-tree of the scene graph that has this actor at
2433    * the root.
2434    */
2435   clutter_actor_maybe_layout_children (self, box, flags);
2436
2437   if (changed)
2438     {
2439       ClutterActorBox signal_box = priv->allocation;
2440       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2441
2442       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2443                      &signal_box,
2444                      signal_flags);
2445     }
2446
2447   g_object_thaw_notify (G_OBJECT (self));
2448 }
2449
2450 static void
2451 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2452                                     ClutterActor *origin)
2453 {
2454   /* no point in queuing a redraw on a destroyed actor */
2455   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2456     return;
2457
2458   /* NB: We can't bail out early here if the actor is hidden in case
2459    * the actor bas been cloned. In this case the clone will need to
2460    * receive the signal so it can queue its own redraw.
2461    */
2462
2463   /* calls klass->queue_redraw in default handler */
2464   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2465 }
2466
2467 static void
2468 clutter_actor_real_queue_redraw (ClutterActor *self,
2469                                  ClutterActor *origin)
2470 {
2471   ClutterActor *parent;
2472
2473   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2474                 _clutter_actor_get_debug_name (self),
2475                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2476                                : "same actor");
2477
2478   /* no point in queuing a redraw on a destroyed actor */
2479   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2480     return;
2481
2482   /* If the queue redraw is coming from a child then the actor has
2483      become dirty and any queued effect is no longer valid */
2484   if (self != origin)
2485     {
2486       self->priv->is_dirty = TRUE;
2487       self->priv->effect_to_redraw = NULL;
2488     }
2489
2490   /* If the actor isn't visible, we still had to emit the signal
2491    * to allow for a ClutterClone, but the appearance of the parent
2492    * won't change so we don't have to propagate up the hierarchy.
2493    */
2494   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2495     return;
2496
2497   /* Although we could determine here that a full stage redraw
2498    * has already been queued and immediately bail out, we actually
2499    * guarantee that we will propagate a queue-redraw signal to our
2500    * parent at least once so that it's possible to implement a
2501    * container that tracks which of its children have queued a
2502    * redraw.
2503    */
2504   if (self->priv->propagated_one_redraw)
2505     {
2506       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2507       if (stage != NULL &&
2508           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2509         return;
2510     }
2511
2512   self->priv->propagated_one_redraw = TRUE;
2513
2514   /* notify parents, if they are all visible eventually we'll
2515    * queue redraw on the stage, which queues the redraw idle.
2516    */
2517   parent = clutter_actor_get_parent (self);
2518   if (parent != NULL)
2519     {
2520       /* this will go up recursively */
2521       _clutter_actor_signal_queue_redraw (parent, origin);
2522     }
2523 }
2524
2525 static void
2526 clutter_actor_real_queue_relayout (ClutterActor *self)
2527 {
2528   ClutterActorPrivate *priv = self->priv;
2529
2530   /* no point in queueing a redraw on a destroyed actor */
2531   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2532     return;
2533
2534   priv->needs_width_request  = TRUE;
2535   priv->needs_height_request = TRUE;
2536   priv->needs_allocation     = TRUE;
2537
2538   /* reset the cached size requests */
2539   memset (priv->width_requests, 0,
2540           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2541   memset (priv->height_requests, 0,
2542           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2543
2544   /* We need to go all the way up the hierarchy */
2545   if (priv->parent != NULL)
2546     _clutter_actor_queue_only_relayout (priv->parent);
2547 }
2548
2549 /**
2550  * clutter_actor_apply_relative_transform_to_point:
2551  * @self: A #ClutterActor
2552  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2553  *   default #ClutterStage
2554  * @point: A point as #ClutterVertex
2555  * @vertex: (out caller-allocates): The translated #ClutterVertex
2556  *
2557  * Transforms @point in coordinates relative to the actor into
2558  * ancestor-relative coordinates using the relevant transform
2559  * stack (i.e. scale, rotation, etc).
2560  *
2561  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2562  * this case, the coordinates returned will be the coordinates on
2563  * the stage before the projection is applied. This is different from
2564  * the behaviour of clutter_actor_apply_transform_to_point().
2565  *
2566  * Since: 0.6
2567  */
2568 void
2569 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2570                                                  ClutterActor        *ancestor,
2571                                                  const ClutterVertex *point,
2572                                                  ClutterVertex       *vertex)
2573 {
2574   gfloat w;
2575   CoglMatrix matrix;
2576
2577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2578   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2579   g_return_if_fail (point != NULL);
2580   g_return_if_fail (vertex != NULL);
2581
2582   *vertex = *point;
2583   w = 1.0;
2584
2585   if (ancestor == NULL)
2586     ancestor = _clutter_actor_get_stage_internal (self);
2587
2588   if (ancestor == NULL)
2589     {
2590       *vertex = *point;
2591       return;
2592     }
2593
2594   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2595   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2596 }
2597
2598 static gboolean
2599 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2600                                          const ClutterVertex *vertices_in,
2601                                          ClutterVertex *vertices_out,
2602                                          int n_vertices)
2603 {
2604   ClutterActor *stage;
2605   CoglMatrix modelview;
2606   CoglMatrix projection;
2607   float viewport[4];
2608
2609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2610
2611   stage = _clutter_actor_get_stage_internal (self);
2612
2613   /* We really can't do anything meaningful in this case so don't try
2614    * to do any transform */
2615   if (stage == NULL)
2616     return FALSE;
2617
2618   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2619    * that gets us to stage coordinates, we want to go all the way to eye
2620    * coordinates */
2621   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2622
2623   /* Fetch the projection and viewport */
2624   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2625   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2626                                &viewport[0],
2627                                &viewport[1],
2628                                &viewport[2],
2629                                &viewport[3]);
2630
2631   _clutter_util_fully_transform_vertices (&modelview,
2632                                           &projection,
2633                                           viewport,
2634                                           vertices_in,
2635                                           vertices_out,
2636                                           n_vertices);
2637
2638   return TRUE;
2639 }
2640
2641 /**
2642  * clutter_actor_apply_transform_to_point:
2643  * @self: A #ClutterActor
2644  * @point: A point as #ClutterVertex
2645  * @vertex: (out caller-allocates): The translated #ClutterVertex
2646  *
2647  * Transforms @point in coordinates relative to the actor
2648  * into screen-relative coordinates with the current actor
2649  * transformation (i.e. scale, rotation, etc)
2650  *
2651  * Since: 0.4
2652  **/
2653 void
2654 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2655                                         const ClutterVertex *point,
2656                                         ClutterVertex       *vertex)
2657 {
2658   g_return_if_fail (point != NULL);
2659   g_return_if_fail (vertex != NULL);
2660   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2661 }
2662
2663 /*
2664  * _clutter_actor_get_relative_transformation_matrix:
2665  * @self: The actor whose coordinate space you want to transform from.
2666  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2667  *            or %NULL if you want to transform all the way to eye coordinates.
2668  * @matrix: A #CoglMatrix to store the transformation
2669  *
2670  * This gets a transformation @matrix that will transform coordinates from the
2671  * coordinate space of @self into the coordinate space of @ancestor.
2672  *
2673  * For example if you need a matrix that can transform the local actor
2674  * coordinates of @self into stage coordinates you would pass the actor's stage
2675  * pointer as the @ancestor.
2676  *
2677  * If you pass %NULL then the transformation will take you all the way through
2678  * to eye coordinates. This can be useful if you want to extract the entire
2679  * modelview transform that Clutter applies before applying the projection
2680  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2681  * using cogl_set_modelview_matrix() for example then you would want a matrix
2682  * that transforms into eye coordinates.
2683  *
2684  * <note><para>This function explicitly initializes the given @matrix. If you just
2685  * want clutter to multiply a relative transformation with an existing matrix
2686  * you can use clutter_actor_apply_relative_transformation_matrix()
2687  * instead.</para></note>
2688  *
2689  */
2690 /* XXX: We should consider caching the stage relative modelview along with
2691  * the actor itself */
2692 static void
2693 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2694                                                    ClutterActor *ancestor,
2695                                                    CoglMatrix *matrix)
2696 {
2697   cogl_matrix_init_identity (matrix);
2698
2699   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2700 }
2701
2702 /* Project the given @box into stage window coordinates, writing the
2703  * transformed vertices to @verts[]. */
2704 static gboolean
2705 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2706                                           const ClutterActorBox *box,
2707                                           ClutterVertex          verts[])
2708 {
2709   ClutterVertex box_vertices[4];
2710
2711   box_vertices[0].x = box->x1;
2712   box_vertices[0].y = box->y1;
2713   box_vertices[0].z = 0;
2714   box_vertices[1].x = box->x2;
2715   box_vertices[1].y = box->y1;
2716   box_vertices[1].z = 0;
2717   box_vertices[2].x = box->x1;
2718   box_vertices[2].y = box->y2;
2719   box_vertices[2].z = 0;
2720   box_vertices[3].x = box->x2;
2721   box_vertices[3].y = box->y2;
2722   box_vertices[3].z = 0;
2723
2724   return
2725     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2726 }
2727
2728 /**
2729  * clutter_actor_get_allocation_vertices:
2730  * @self: A #ClutterActor
2731  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2732  *   against, or %NULL to use the #ClutterStage
2733  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2734  *   location for an array of 4 #ClutterVertex in which to store the result
2735  *
2736  * Calculates the transformed coordinates of the four corners of the
2737  * actor in the plane of @ancestor. The returned vertices relate to
2738  * the #ClutterActorBox coordinates as follows:
2739  * <itemizedlist>
2740  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2741  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2742  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2743  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2744  * </itemizedlist>
2745  *
2746  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2747  * this case, the coordinates returned will be the coordinates on
2748  * the stage before the projection is applied. This is different from
2749  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2750  *
2751  * Since: 0.6
2752  */
2753 void
2754 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2755                                        ClutterActor  *ancestor,
2756                                        ClutterVertex  verts[])
2757 {
2758   ClutterActorPrivate *priv;
2759   ClutterActorBox box;
2760   ClutterVertex vertices[4];
2761   CoglMatrix modelview;
2762
2763   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2764   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2765
2766   if (ancestor == NULL)
2767     ancestor = _clutter_actor_get_stage_internal (self);
2768
2769   /* Fallback to a NOP transform if the actor isn't parented under a
2770    * stage. */
2771   if (ancestor == NULL)
2772     ancestor = self;
2773
2774   priv = self->priv;
2775
2776   /* if the actor needs to be allocated we force a relayout, so that
2777    * we will have valid values to use in the transformations */
2778   if (priv->needs_allocation)
2779     {
2780       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2781       if (stage)
2782         _clutter_stage_maybe_relayout (stage);
2783       else
2784         {
2785           box.x1 = box.y1 = 0;
2786           /* The result isn't really meaningful in this case but at
2787            * least try to do something *vaguely* reasonable... */
2788           clutter_actor_get_size (self, &box.x2, &box.y2);
2789         }
2790     }
2791
2792   clutter_actor_get_allocation_box (self, &box);
2793
2794   vertices[0].x = box.x1;
2795   vertices[0].y = box.y1;
2796   vertices[0].z = 0;
2797   vertices[1].x = box.x2;
2798   vertices[1].y = box.y1;
2799   vertices[1].z = 0;
2800   vertices[2].x = box.x1;
2801   vertices[2].y = box.y2;
2802   vertices[2].z = 0;
2803   vertices[3].x = box.x2;
2804   vertices[3].y = box.y2;
2805   vertices[3].z = 0;
2806
2807   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2808                                                      &modelview);
2809
2810   cogl_matrix_transform_points (&modelview,
2811                                 3,
2812                                 sizeof (ClutterVertex),
2813                                 vertices,
2814                                 sizeof (ClutterVertex),
2815                                 vertices,
2816                                 4);
2817 }
2818
2819 /**
2820  * clutter_actor_get_abs_allocation_vertices:
2821  * @self: A #ClutterActor
2822  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2823  *   of 4 #ClutterVertex where to store the result.
2824  *
2825  * Calculates the transformed screen coordinates of the four corners of
2826  * the actor; the returned vertices relate to the #ClutterActorBox
2827  * coordinates  as follows:
2828  * <itemizedlist>
2829  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2830  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2831  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2832  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2833  * </itemizedlist>
2834  *
2835  * Since: 0.4
2836  */
2837 void
2838 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2839                                            ClutterVertex  verts[])
2840 {
2841   ClutterActorPrivate *priv;
2842   ClutterActorBox actor_space_allocation;
2843
2844   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2845
2846   priv = self->priv;
2847
2848   /* if the actor needs to be allocated we force a relayout, so that
2849    * the actor allocation box will be valid for
2850    * _clutter_actor_transform_and_project_box()
2851    */
2852   if (priv->needs_allocation)
2853     {
2854       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2855       /* There's nothing meaningful we can do now */
2856       if (!stage)
2857         return;
2858
2859       _clutter_stage_maybe_relayout (stage);
2860     }
2861
2862   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2863    * own coordinate space... */
2864   actor_space_allocation.x1 = 0;
2865   actor_space_allocation.y1 = 0;
2866   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2867   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2868   _clutter_actor_transform_and_project_box (self,
2869                                             &actor_space_allocation,
2870                                             verts);
2871 }
2872
2873 static void
2874 clutter_actor_real_apply_transform (ClutterActor *self,
2875                                     CoglMatrix   *matrix)
2876 {
2877   ClutterActorPrivate *priv = self->priv;
2878
2879   if (!priv->transform_valid)
2880     {
2881       CoglMatrix *transform = &priv->transform;
2882       const ClutterTransformInfo *info;
2883
2884       info = _clutter_actor_get_transform_info_or_defaults (self);
2885
2886       cogl_matrix_init_identity (transform);
2887
2888       cogl_matrix_translate (transform,
2889                              priv->allocation.x1,
2890                              priv->allocation.y1,
2891                              0.0);
2892
2893       if (info->depth)
2894         cogl_matrix_translate (transform, 0, 0, info->depth);
2895
2896       /*
2897        * because the rotation involves translations, we must scale
2898        * before applying the rotations (if we apply the scale after
2899        * the rotations, the translations included in the rotation are
2900        * not scaled and so the entire object will move on the screen
2901        * as a result of rotating it).
2902        */
2903       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2904         {
2905           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2906                                         &info->scale_center,
2907                                         cogl_matrix_scale (transform,
2908                                                            info->scale_x,
2909                                                            info->scale_y,
2910                                                            1.0));
2911         }
2912
2913       if (info->rz_angle)
2914         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2915                                       &info->rz_center,
2916                                       cogl_matrix_rotate (transform,
2917                                                           info->rz_angle,
2918                                                           0, 0, 1.0));
2919
2920       if (info->ry_angle)
2921         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2922                                       &info->ry_center,
2923                                       cogl_matrix_rotate (transform,
2924                                                           info->ry_angle,
2925                                                           0, 1.0, 0));
2926
2927       if (info->rx_angle)
2928         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2929                                       &info->rx_center,
2930                                       cogl_matrix_rotate (transform,
2931                                                           info->rx_angle,
2932                                                           1.0, 0, 0));
2933
2934       if (!clutter_anchor_coord_is_zero (&info->anchor))
2935         {
2936           gfloat x, y, z;
2937
2938           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2939           cogl_matrix_translate (transform, -x, -y, -z);
2940         }
2941
2942       priv->transform_valid = TRUE;
2943     }
2944
2945   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2946 }
2947
2948 /* Applies the transforms associated with this actor to the given
2949  * matrix. */
2950 void
2951 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2952                                           CoglMatrix *matrix)
2953 {
2954   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2955 }
2956
2957 /*
2958  * clutter_actor_apply_relative_transformation_matrix:
2959  * @self: The actor whose coordinate space you want to transform from.
2960  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2961  *            or %NULL if you want to transform all the way to eye coordinates.
2962  * @matrix: A #CoglMatrix to apply the transformation too.
2963  *
2964  * This multiplies a transform with @matrix that will transform coordinates
2965  * from the coordinate space of @self into the coordinate space of @ancestor.
2966  *
2967  * For example if you need a matrix that can transform the local actor
2968  * coordinates of @self into stage coordinates you would pass the actor's stage
2969  * pointer as the @ancestor.
2970  *
2971  * If you pass %NULL then the transformation will take you all the way through
2972  * to eye coordinates. This can be useful if you want to extract the entire
2973  * modelview transform that Clutter applies before applying the projection
2974  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2975  * using cogl_set_modelview_matrix() for example then you would want a matrix
2976  * that transforms into eye coordinates.
2977  *
2978  * <note>This function doesn't initialize the given @matrix, it simply
2979  * multiplies the requested transformation matrix with the existing contents of
2980  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2981  * before calling this function, or you can use
2982  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2983  */
2984 void
2985 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2986                                                      ClutterActor *ancestor,
2987                                                      CoglMatrix *matrix)
2988 {
2989   ClutterActor *parent;
2990
2991   /* Note we terminate before ever calling stage->apply_transform()
2992    * since that would conceptually be relative to the underlying
2993    * window OpenGL coordinates so we'd need a special @ancestor
2994    * value to represent the fake parent of the stage. */
2995   if (self == ancestor)
2996     return;
2997
2998   parent = clutter_actor_get_parent (self);
2999
3000   if (parent != NULL)
3001     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3002                                                          matrix);
3003
3004   _clutter_actor_apply_modelview_transform (self, matrix);
3005 }
3006
3007 static void
3008 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3009                                        ClutterPaintVolume *pv,
3010                                        const char *label,
3011                                        const CoglColor *color)
3012 {
3013   static CoglPipeline *outline = NULL;
3014   CoglPrimitive *prim;
3015   ClutterVertex line_ends[12 * 2];
3016   int n_vertices;
3017   CoglContext *ctx =
3018     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3019   /* XXX: at some point we'll query this from the stage but we can't
3020    * do that until the osx backend uses Cogl natively. */
3021   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3022
3023   if (outline == NULL)
3024     outline = cogl_pipeline_new (ctx);
3025
3026   _clutter_paint_volume_complete (pv);
3027
3028   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3029
3030   /* Front face */
3031   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3032   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3033   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3034   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3035
3036   if (!pv->is_2d)
3037     {
3038       /* Back face */
3039       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3040       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3041       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3042       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3043
3044       /* Lines connecting front face to back face */
3045       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3046       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3047       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3048       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3049     }
3050
3051   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3052                                 n_vertices,
3053                                 (CoglVertexP3 *)line_ends);
3054
3055   cogl_pipeline_set_color (outline, color);
3056   cogl_framebuffer_draw_primitive (fb, outline, prim);
3057   cogl_object_unref (prim);
3058
3059   if (label)
3060     {
3061       PangoLayout *layout;
3062       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3063       pango_layout_set_text (layout, label, -1);
3064       cogl_pango_render_layout (layout,
3065                                 pv->vertices[0].x,
3066                                 pv->vertices[0].y,
3067                                 color,
3068                                 0);
3069       g_object_unref (layout);
3070     }
3071 }
3072
3073 static void
3074 _clutter_actor_draw_paint_volume (ClutterActor *self)
3075 {
3076   ClutterPaintVolume *pv;
3077   CoglColor color;
3078
3079   pv = _clutter_actor_get_paint_volume_mutable (self);
3080   if (!pv)
3081     {
3082       gfloat width, height;
3083       ClutterPaintVolume fake_pv;
3084
3085       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3086       _clutter_paint_volume_init_static (&fake_pv, stage);
3087
3088       clutter_actor_get_size (self, &width, &height);
3089       clutter_paint_volume_set_width (&fake_pv, width);
3090       clutter_paint_volume_set_height (&fake_pv, height);
3091
3092       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3093       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3094                                              _clutter_actor_get_debug_name (self),
3095                                              &color);
3096
3097       clutter_paint_volume_free (&fake_pv);
3098     }
3099   else
3100     {
3101       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3102       _clutter_actor_draw_paint_volume_full (self, pv,
3103                                              _clutter_actor_get_debug_name (self),
3104                                              &color);
3105     }
3106 }
3107
3108 static void
3109 _clutter_actor_paint_cull_result (ClutterActor *self,
3110                                   gboolean success,
3111                                   ClutterCullResult result)
3112 {
3113   ClutterPaintVolume *pv;
3114   CoglColor color;
3115
3116   if (success)
3117     {
3118       if (result == CLUTTER_CULL_RESULT_IN)
3119         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3120       else if (result == CLUTTER_CULL_RESULT_OUT)
3121         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3122       else
3123         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3124     }
3125   else
3126     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3127
3128   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3129     _clutter_actor_draw_paint_volume_full (self, pv,
3130                                            _clutter_actor_get_debug_name (self),
3131                                            &color);
3132   else
3133     {
3134       PangoLayout *layout;
3135       char *label =
3136         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3137       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3138       cogl_set_source_color (&color);
3139
3140       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3141       pango_layout_set_text (layout, label, -1);
3142       cogl_pango_render_layout (layout,
3143                                 0,
3144                                 0,
3145                                 &color,
3146                                 0);
3147       g_free (label);
3148       g_object_unref (layout);
3149     }
3150 }
3151
3152 static int clone_paint_level = 0;
3153
3154 void
3155 _clutter_actor_push_clone_paint (void)
3156 {
3157   clone_paint_level++;
3158 }
3159
3160 void
3161 _clutter_actor_pop_clone_paint (void)
3162 {
3163   clone_paint_level--;
3164 }
3165
3166 static gboolean
3167 in_clone_paint (void)
3168 {
3169   return clone_paint_level > 0;
3170 }
3171
3172 /* Returns TRUE if the actor can be ignored */
3173 /* FIXME: we should return a ClutterCullResult, and
3174  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3175  * means there's no point in trying to cull descendants of the current
3176  * node. */
3177 static gboolean
3178 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3179 {
3180   ClutterActorPrivate *priv = self->priv;
3181   ClutterActor *stage;
3182   const ClutterPlane *stage_clip;
3183
3184   if (!priv->last_paint_volume_valid)
3185     {
3186       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3187                     "->last_paint_volume_valid == FALSE",
3188                     _clutter_actor_get_debug_name (self));
3189       return FALSE;
3190     }
3191
3192   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3193     return FALSE;
3194
3195   stage = _clutter_actor_get_stage_internal (self);
3196   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3197   if (G_UNLIKELY (!stage_clip))
3198     {
3199       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3200                     "No stage clip set",
3201                     _clutter_actor_get_debug_name (self));
3202       return FALSE;
3203     }
3204
3205   if (cogl_get_draw_framebuffer () !=
3206       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3207     {
3208       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3209                     "Current framebuffer doesn't correspond to stage",
3210                     _clutter_actor_get_debug_name (self));
3211       return FALSE;
3212     }
3213
3214   *result_out =
3215     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3216   return TRUE;
3217 }
3218
3219 static void
3220 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3221 {
3222   ClutterActorPrivate *priv = self->priv;
3223   const ClutterPaintVolume *pv;
3224
3225   if (priv->last_paint_volume_valid)
3226     {
3227       clutter_paint_volume_free (&priv->last_paint_volume);
3228       priv->last_paint_volume_valid = FALSE;
3229     }
3230
3231   pv = clutter_actor_get_paint_volume (self);
3232   if (!pv)
3233     {
3234       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3235                     "Actor failed to report a paint volume",
3236                     _clutter_actor_get_debug_name (self));
3237       return;
3238     }
3239
3240   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3241
3242   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3243                                             NULL); /* eye coordinates */
3244
3245   priv->last_paint_volume_valid = TRUE;
3246 }
3247
3248 static inline gboolean
3249 actor_has_shader_data (ClutterActor *self)
3250 {
3251   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3252 }
3253
3254 guint32
3255 _clutter_actor_get_pick_id (ClutterActor *self)
3256 {
3257   if (self->priv->pick_id < 0)
3258     return 0;
3259
3260   return self->priv->pick_id;
3261 }
3262
3263 /* This is the same as clutter_actor_add_effect except that it doesn't
3264    queue a redraw and it doesn't notify on the effect property */
3265 static void
3266 _clutter_actor_add_effect_internal (ClutterActor  *self,
3267                                     ClutterEffect *effect)
3268 {
3269   ClutterActorPrivate *priv = self->priv;
3270
3271   if (priv->effects == NULL)
3272     {
3273       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3274       priv->effects->actor = self;
3275     }
3276
3277   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3278 }
3279
3280 /* This is the same as clutter_actor_remove_effect except that it doesn't
3281    queue a redraw and it doesn't notify on the effect property */
3282 static void
3283 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3284                                        ClutterEffect *effect)
3285 {
3286   ClutterActorPrivate *priv = self->priv;
3287
3288   if (priv->effects == NULL)
3289     return;
3290
3291   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3292
3293   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3294     g_clear_object (&priv->effects);
3295 }
3296
3297 static gboolean
3298 needs_flatten_effect (ClutterActor *self)
3299 {
3300   ClutterActorPrivate *priv = self->priv;
3301
3302   if (G_UNLIKELY (clutter_paint_debug_flags &
3303                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3304     return FALSE;
3305
3306   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3307     return TRUE;
3308   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3309     {
3310       if (clutter_actor_get_paint_opacity (self) < 255 &&
3311           clutter_actor_has_overlaps (self))
3312         return TRUE;
3313     }
3314
3315   return FALSE;
3316 }
3317
3318 static void
3319 add_or_remove_flatten_effect (ClutterActor *self)
3320 {
3321   ClutterActorPrivate *priv = self->priv;
3322
3323   /* Add or remove the flatten effect depending on the
3324      offscreen-redirect property. */
3325   if (needs_flatten_effect (self))
3326     {
3327       if (priv->flatten_effect == NULL)
3328         {
3329           ClutterActorMeta *actor_meta;
3330           gint priority;
3331
3332           priv->flatten_effect = _clutter_flatten_effect_new ();
3333           /* Keep a reference to the effect so that we can queue
3334              redraws from it */
3335           g_object_ref_sink (priv->flatten_effect);
3336
3337           /* Set the priority of the effect to high so that it will
3338              always be applied to the actor first. It uses an internal
3339              priority so that it won't be visible to applications */
3340           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3341           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3342           _clutter_actor_meta_set_priority (actor_meta, priority);
3343
3344           /* This will add the effect without queueing a redraw */
3345           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3346         }
3347     }
3348   else
3349     {
3350       if (priv->flatten_effect != NULL)
3351         {
3352           /* Destroy the effect so that it will lose its fbo cache of
3353              the actor */
3354           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3355           g_clear_object (&priv->flatten_effect);
3356         }
3357     }
3358 }
3359
3360 static void
3361 clutter_actor_real_paint (ClutterActor *actor)
3362 {
3363   ClutterActorPrivate *priv = actor->priv;
3364   ClutterActor *iter;
3365
3366   for (iter = priv->first_child;
3367        iter != NULL;
3368        iter = iter->priv->next_sibling)
3369     {
3370       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3371                     _clutter_actor_get_debug_name (iter),
3372                     _clutter_actor_get_debug_name (actor),
3373                     iter->priv->allocation.x1,
3374                     iter->priv->allocation.y1,
3375                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3376                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3377
3378       clutter_actor_paint (iter);
3379     }
3380 }
3381
3382 static gboolean
3383 clutter_actor_paint_node (ClutterActor     *actor,
3384                           ClutterPaintNode *root)
3385 {
3386   ClutterActorPrivate *priv = actor->priv;
3387
3388   if (root == NULL)
3389     return FALSE;
3390
3391   if (priv->bg_color_set &&
3392       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3393     {
3394       ClutterPaintNode *node;
3395       ClutterColor bg_color;
3396       ClutterActorBox box;
3397
3398       box.x1 = 0.f;
3399       box.y1 = 0.f;
3400       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3401       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3402
3403       bg_color = priv->bg_color;
3404       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3405                      * priv->bg_color.alpha
3406                      / 255;
3407
3408       node = clutter_color_node_new (&bg_color);
3409       clutter_paint_node_set_name (node, "backgroundColor");
3410       clutter_paint_node_add_rectangle (node, &box);
3411       clutter_paint_node_add_child (root, node);
3412       clutter_paint_node_unref (node);
3413     }
3414
3415   if (priv->content != NULL)
3416     _clutter_content_paint_content (priv->content, actor, root);
3417
3418   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3419     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3420
3421   if (clutter_paint_node_get_n_children (root) == 0)
3422     return FALSE;
3423
3424 #ifdef CLUTTER_ENABLE_DEBUG
3425   if (CLUTTER_HAS_DEBUG (PAINT))
3426     {
3427       /* dump the tree only if we have one */
3428       _clutter_paint_node_dump_tree (root);
3429     }
3430 #endif /* CLUTTER_ENABLE_DEBUG */
3431
3432   _clutter_paint_node_paint (root);
3433
3434 #if 0
3435   /* XXX: Uncomment this when we disable emitting the paint signal */
3436   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3437 #endif
3438
3439   return TRUE;
3440 }
3441
3442 /**
3443  * clutter_actor_paint:
3444  * @self: A #ClutterActor
3445  *
3446  * Renders the actor to display.
3447  *
3448  * This function should not be called directly by applications.
3449  * Call clutter_actor_queue_redraw() to queue paints, instead.
3450  *
3451  * This function is context-aware, and will either cause a
3452  * regular paint or a pick paint.
3453  *
3454  * This function will emit the #ClutterActor::paint signal or
3455  * the #ClutterActor::pick signal, depending on the context.
3456  *
3457  * This function does not paint the actor if the actor is set to 0,
3458  * unless it is performing a pick paint.
3459  */
3460 void
3461 clutter_actor_paint (ClutterActor *self)
3462 {
3463   ClutterActorPrivate *priv;
3464   ClutterPickMode pick_mode;
3465   gboolean clip_set = FALSE;
3466   gboolean shader_applied = FALSE;
3467
3468   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3469                           "Actor real-paint counter",
3470                           "Increments each time any actor is painted",
3471                           0 /* no application private data */);
3472   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3473                           "Actor pick-paint counter",
3474                           "Increments each time any actor is painted "
3475                           "for picking",
3476                           0 /* no application private data */);
3477
3478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3479
3480   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3481     return;
3482
3483   priv = self->priv;
3484
3485   pick_mode = _clutter_context_get_pick_mode ();
3486
3487   if (pick_mode == CLUTTER_PICK_NONE)
3488     priv->propagated_one_redraw = FALSE;
3489
3490   /* It's an important optimization that we consider painting of
3491    * actors with 0 opacity to be a NOP... */
3492   if (pick_mode == CLUTTER_PICK_NONE &&
3493       /* ignore top-levels, since they might be transparent */
3494       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3495       /* Use the override opacity if its been set */
3496       ((priv->opacity_override >= 0) ?
3497        priv->opacity_override : priv->opacity) == 0)
3498     return;
3499
3500   /* if we aren't paintable (not in a toplevel with all
3501    * parents paintable) then do nothing.
3502    */
3503   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3504     return;
3505
3506   /* mark that we are in the paint process */
3507   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3508
3509   cogl_push_matrix();
3510
3511   if (priv->enable_model_view_transform)
3512     {
3513       CoglMatrix matrix;
3514
3515       /* XXX: It could be better to cache the modelview with the actor
3516        * instead of progressively building up the transformations on
3517        * the matrix stack every time we paint. */
3518       cogl_get_modelview_matrix (&matrix);
3519       _clutter_actor_apply_modelview_transform (self, &matrix);
3520
3521 #ifdef CLUTTER_ENABLE_DEBUG
3522       /* Catch when out-of-band transforms have been made by actors not as part
3523        * of an apply_transform vfunc... */
3524       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3525         {
3526           CoglMatrix expected_matrix;
3527
3528           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3529                                                              &expected_matrix);
3530
3531           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3532             {
3533               GString *buf = g_string_sized_new (1024);
3534               ClutterActor *parent;
3535
3536               parent = self;
3537               while (parent != NULL)
3538                 {
3539                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3540
3541                   if (parent->priv->parent != NULL)
3542                     g_string_append (buf, "->");
3543
3544                   parent = parent->priv->parent;
3545                 }
3546
3547               g_warning ("Unexpected transform found when painting actor "
3548                          "\"%s\". This will be caused by one of the actor's "
3549                          "ancestors (%s) using the Cogl API directly to transform "
3550                          "children instead of using ::apply_transform().",
3551                          _clutter_actor_get_debug_name (self),
3552                          buf->str);
3553
3554               g_string_free (buf, TRUE);
3555             }
3556         }
3557 #endif /* CLUTTER_ENABLE_DEBUG */
3558
3559       cogl_set_modelview_matrix (&matrix);
3560     }
3561
3562   if (priv->has_clip)
3563     {
3564       cogl_clip_push_rectangle (priv->clip.x,
3565                                 priv->clip.y,
3566                                 priv->clip.x + priv->clip.width,
3567                                 priv->clip.y + priv->clip.height);
3568       clip_set = TRUE;
3569     }
3570   else if (priv->clip_to_allocation)
3571     {
3572       gfloat width, height;
3573
3574       width  = priv->allocation.x2 - priv->allocation.x1;
3575       height = priv->allocation.y2 - priv->allocation.y1;
3576
3577       cogl_clip_push_rectangle (0, 0, width, height);
3578       clip_set = TRUE;
3579     }
3580
3581   if (pick_mode == CLUTTER_PICK_NONE)
3582     {
3583       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3584
3585       /* We check whether we need to add the flatten effect before
3586          each paint so that we can avoid having a mechanism for
3587          applications to notify when the value of the
3588          has_overlaps virtual changes. */
3589       add_or_remove_flatten_effect (self);
3590     }
3591   else
3592     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3593
3594   /* We save the current paint volume so that the next time the
3595    * actor queues a redraw we can constrain the redraw to just
3596    * cover the union of the new bounding box and the old.
3597    *
3598    * We also fetch the current paint volume to perform culling so
3599    * we can avoid painting actors outside the current clip region.
3600    *
3601    * If we are painting inside a clone, we should neither update
3602    * the paint volume or use it to cull painting, since the paint
3603    * box represents the location of the source actor on the
3604    * screen.
3605    *
3606    * XXX: We are starting to do a lot of vertex transforms on
3607    * the CPU in a typical paint, so at some point we should
3608    * audit these and consider caching some things.
3609    *
3610    * NB: We don't perform culling while picking at this point because
3611    * clutter-stage.c doesn't setup the clipping planes appropriately.
3612    *
3613    * NB: We don't want to update the last-paint-volume during picking
3614    * because the last-paint-volume is used to determine the old screen
3615    * space location of an actor that has moved so we can know the
3616    * minimal region to redraw to clear an old view of the actor. If we
3617    * update this during picking then by the time we come around to
3618    * paint then the last-paint-volume would likely represent the new
3619    * actor position not the old.
3620    */
3621   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3622     {
3623       gboolean success;
3624       /* annoyingly gcc warns if uninitialized even though
3625        * the initialization is redundant :-( */
3626       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3627
3628       if (G_LIKELY ((clutter_paint_debug_flags &
3629                      (CLUTTER_DEBUG_DISABLE_CULLING |
3630                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3631                     (CLUTTER_DEBUG_DISABLE_CULLING |
3632                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3633         _clutter_actor_update_last_paint_volume (self);
3634
3635       success = cull_actor (self, &result);
3636
3637       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3638         _clutter_actor_paint_cull_result (self, success, result);
3639       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3640         goto done;
3641     }
3642
3643   if (priv->effects == NULL)
3644     {
3645       if (pick_mode == CLUTTER_PICK_NONE &&
3646           actor_has_shader_data (self))
3647         {
3648           _clutter_actor_shader_pre_paint (self, FALSE);
3649           shader_applied = TRUE;
3650         }
3651
3652       priv->next_effect_to_paint = NULL;
3653     }
3654   else
3655     priv->next_effect_to_paint =
3656       _clutter_meta_group_peek_metas (priv->effects);
3657
3658   clutter_actor_continue_paint (self);
3659
3660   if (shader_applied)
3661     _clutter_actor_shader_post_paint (self);
3662
3663   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3664                   pick_mode == CLUTTER_PICK_NONE))
3665     _clutter_actor_draw_paint_volume (self);
3666
3667 done:
3668   /* If we make it here then the actor has run through a complete
3669      paint run including all the effects so it's no longer dirty */
3670   if (pick_mode == CLUTTER_PICK_NONE)
3671     priv->is_dirty = FALSE;
3672
3673   if (clip_set)
3674     cogl_clip_pop();
3675
3676   cogl_pop_matrix();
3677
3678   /* paint sequence complete */
3679   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3680 }
3681
3682 /**
3683  * clutter_actor_continue_paint:
3684  * @self: A #ClutterActor
3685  *
3686  * Run the next stage of the paint sequence. This function should only
3687  * be called within the implementation of the ‘run’ virtual of a
3688  * #ClutterEffect. It will cause the run method of the next effect to
3689  * be applied, or it will paint the actual actor if the current effect
3690  * is the last effect in the chain.
3691  *
3692  * Since: 1.8
3693  */
3694 void
3695 clutter_actor_continue_paint (ClutterActor *self)
3696 {
3697   ClutterActorPrivate *priv;
3698
3699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3700   /* This should only be called from with in the ‘run’ implementation
3701      of a ClutterEffect */
3702   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3703
3704   priv = self->priv;
3705
3706   /* Skip any effects that are disabled */
3707   while (priv->next_effect_to_paint &&
3708          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3709     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3710
3711   /* If this has come from the last effect then we'll just paint the
3712      actual actor */
3713   if (priv->next_effect_to_paint == NULL)
3714     {
3715       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3716         {
3717           ClutterPaintNode *dummy;
3718
3719           /* XXX - this will go away in 2.0, when we can get rid of this
3720            * stuff and switch to a pure retained render tree of PaintNodes
3721            * for the entire frame, starting from the Stage; the paint()
3722            * virtual function can then be called directly.
3723            */
3724           dummy = _clutter_dummy_node_new (self);
3725           clutter_paint_node_set_name (dummy, "Root");
3726
3727           /* XXX - for 1.12, we use the return value of paint_node() to
3728            * decide whether we should emit the ::paint signal.
3729            */
3730           clutter_actor_paint_node (self, dummy);
3731           clutter_paint_node_unref (dummy);
3732
3733           g_signal_emit (self, actor_signals[PAINT], 0);
3734         }
3735       else
3736         {
3737           ClutterColor col = { 0, };
3738
3739           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3740
3741           /* Actor will then paint silhouette of itself in supplied
3742            * color.  See clutter_stage_get_actor_at_pos() for where
3743            * picking is enabled.
3744            */
3745           g_signal_emit (self, actor_signals[PICK], 0, &col);
3746         }
3747     }
3748   else
3749     {
3750       ClutterEffect *old_current_effect;
3751       ClutterEffectPaintFlags run_flags = 0;
3752
3753       /* Cache the current effect so that we can put it back before
3754          returning */
3755       old_current_effect = priv->current_effect;
3756
3757       priv->current_effect = priv->next_effect_to_paint->data;
3758       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3759
3760       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3761         {
3762           if (priv->is_dirty)
3763             {
3764               /* If there's an effect queued with this redraw then all
3765                  effects up to that one will be considered dirty. It
3766                  is expected the queued effect will paint the cached
3767                  image and not call clutter_actor_continue_paint again
3768                  (although it should work ok if it does) */
3769               if (priv->effect_to_redraw == NULL ||
3770                   priv->current_effect != priv->effect_to_redraw)
3771                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3772             }
3773
3774           _clutter_effect_paint (priv->current_effect, run_flags);
3775         }
3776       else
3777         {
3778           /* We can't determine when an actor has been modified since
3779              its last pick so lets just assume it has always been
3780              modified */
3781           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3782
3783           _clutter_effect_pick (priv->current_effect, run_flags);
3784         }
3785
3786       priv->current_effect = old_current_effect;
3787     }
3788 }
3789
3790 static ClutterActorTraverseVisitFlags
3791 invalidate_queue_redraw_entry (ClutterActor *self,
3792                                int           depth,
3793                                gpointer      user_data)
3794 {
3795   ClutterActorPrivate *priv = self->priv;
3796
3797   if (priv->queue_redraw_entry != NULL)
3798     {
3799       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3800       priv->queue_redraw_entry = NULL;
3801     }
3802
3803   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3804 }
3805
3806 static inline void
3807 remove_child (ClutterActor *self,
3808               ClutterActor *child)
3809 {
3810   ClutterActor *prev_sibling, *next_sibling;
3811
3812   prev_sibling = child->priv->prev_sibling;
3813   next_sibling = child->priv->next_sibling;
3814
3815   if (prev_sibling != NULL)
3816     prev_sibling->priv->next_sibling = next_sibling;
3817
3818   if (next_sibling != NULL)
3819     next_sibling->priv->prev_sibling = prev_sibling;
3820
3821   if (self->priv->first_child == child)
3822     self->priv->first_child = next_sibling;
3823
3824   if (self->priv->last_child == child)
3825     self->priv->last_child = prev_sibling;
3826
3827   child->priv->parent = NULL;
3828   child->priv->prev_sibling = NULL;
3829   child->priv->next_sibling = NULL;
3830 }
3831
3832 typedef enum {
3833   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3834   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3835   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3836   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3837   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3838   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3839
3840   /* default flags for public API */
3841   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3842                                     REMOVE_CHILD_EMIT_PARENT_SET |
3843                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3844                                     REMOVE_CHILD_CHECK_STATE |
3845                                     REMOVE_CHILD_FLUSH_QUEUE |
3846                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3847
3848   /* flags for legacy/deprecated API */
3849   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3850                                     REMOVE_CHILD_FLUSH_QUEUE |
3851                                     REMOVE_CHILD_EMIT_PARENT_SET |
3852                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3853 } ClutterActorRemoveChildFlags;
3854
3855 /*< private >
3856  * clutter_actor_remove_child_internal:
3857  * @self: a #ClutterActor
3858  * @child: the child of @self that has to be removed
3859  * @flags: control the removal operations
3860  *
3861  * Removes @child from the list of children of @self.
3862  */
3863 static void
3864 clutter_actor_remove_child_internal (ClutterActor                 *self,
3865                                      ClutterActor                 *child,
3866                                      ClutterActorRemoveChildFlags  flags)
3867 {
3868   ClutterActor *old_first, *old_last;
3869   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3870   gboolean flush_queue;
3871   gboolean notify_first_last;
3872   gboolean was_mapped;
3873
3874   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3875   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3876   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3877   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3878   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3879   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3880
3881   g_object_freeze_notify (G_OBJECT (self));
3882
3883   if (destroy_meta)
3884     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3885
3886   if (check_state)
3887     {
3888       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3889
3890       /* we need to unrealize *before* we set parent_actor to NULL,
3891        * because in an unrealize method actors are dissociating from the
3892        * stage, which means they need to be able to
3893        * clutter_actor_get_stage().
3894        *
3895        * yhis should unmap and unrealize, unless we're reparenting.
3896        */
3897       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3898     }
3899   else
3900     was_mapped = FALSE;
3901
3902   if (flush_queue)
3903     {
3904       /* We take this opportunity to invalidate any queue redraw entry
3905        * associated with the actor and descendants since we won't be able to
3906        * determine the appropriate stage after this.
3907        *
3908        * we do this after we updated the mapped state because actors might
3909        * end up queueing redraws inside their mapped/unmapped virtual
3910        * functions, and if we invalidate the redraw entry we could end up
3911        * with an inconsistent state and weird memory corruption. see
3912        * bugs:
3913        *
3914        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3915        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3916        */
3917       _clutter_actor_traverse (child,
3918                                0,
3919                                invalidate_queue_redraw_entry,
3920                                NULL,
3921                                NULL);
3922     }
3923
3924   old_first = self->priv->first_child;
3925   old_last = self->priv->last_child;
3926
3927   remove_child (self, child);
3928
3929   self->priv->n_children -= 1;
3930
3931   self->priv->age += 1;
3932
3933   /* if the child that got removed was visible and set to
3934    * expand then we want to reset the parent's state in
3935    * case the child was the only thing that was making it
3936    * expand.
3937    */
3938   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3939       (child->priv->needs_compute_expand ||
3940        child->priv->needs_x_expand ||
3941        child->priv->needs_y_expand))
3942     {
3943       clutter_actor_queue_compute_expand (self);
3944     }
3945
3946   /* clutter_actor_reparent() will emit ::parent-set for us */
3947   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3948     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3949
3950   /* if the child was mapped then we need to relayout ourselves to account
3951    * for the removed child
3952    */
3953   if (was_mapped)
3954     clutter_actor_queue_relayout (self);
3955
3956   /* we need to emit the signal before dropping the reference */
3957   if (emit_actor_removed)
3958     g_signal_emit_by_name (self, "actor-removed", child);
3959
3960   if (notify_first_last)
3961     {
3962       if (old_first != self->priv->first_child)
3963         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3964
3965       if (old_last != self->priv->last_child)
3966         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3967     }
3968
3969   g_object_thaw_notify (G_OBJECT (self));
3970
3971   /* remove the reference we acquired in clutter_actor_add_child() */
3972   g_object_unref (child);
3973 }
3974
3975 static const ClutterTransformInfo default_transform_info = {
3976   0.0, { 0, },          /* rotation-x */
3977   0.0, { 0, },          /* rotation-y */
3978   0.0, { 0, },          /* rotation-z */
3979
3980   1.0, 1.0, { 0, },     /* scale */
3981
3982   { 0, },               /* anchor */
3983
3984   0.0,                  /* depth */
3985 };
3986
3987 /*< private >
3988  * _clutter_actor_get_transform_info_or_defaults:
3989  * @self: a #ClutterActor
3990  *
3991  * Retrieves the ClutterTransformInfo structure associated to an actor.
3992  *
3993  * If the actor does not have a ClutterTransformInfo structure associated
3994  * to it, then the default structure will be returned.
3995  *
3996  * This function should only be used for getters.
3997  *
3998  * Return value: a const pointer to the ClutterTransformInfo structure
3999  */
4000 const ClutterTransformInfo *
4001 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4002 {
4003   ClutterTransformInfo *info;
4004
4005   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4006   if (info != NULL)
4007     return info;
4008
4009   return &default_transform_info;
4010 }
4011
4012 static void
4013 clutter_transform_info_free (gpointer data)
4014 {
4015   if (data != NULL)
4016     g_slice_free (ClutterTransformInfo, data);
4017 }
4018
4019 /*< private >
4020  * _clutter_actor_get_transform_info:
4021  * @self: a #ClutterActor
4022  *
4023  * Retrieves a pointer to the ClutterTransformInfo structure.
4024  *
4025  * If the actor does not have a ClutterTransformInfo associated to it, one
4026  * will be created and initialized to the default values.
4027  *
4028  * This function should be used for setters.
4029  *
4030  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4031  * instead.
4032  *
4033  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4034  *   structure
4035  */
4036 ClutterTransformInfo *
4037 _clutter_actor_get_transform_info (ClutterActor *self)
4038 {
4039   ClutterTransformInfo *info;
4040
4041   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4042   if (info == NULL)
4043     {
4044       info = g_slice_new (ClutterTransformInfo);
4045
4046       *info = default_transform_info;
4047
4048       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4049                                info,
4050                                clutter_transform_info_free);
4051     }
4052
4053   return info;
4054 }
4055
4056 /*< private >
4057  * clutter_actor_set_rotation_angle_internal:
4058  * @self: a #ClutterActor
4059  * @axis: the axis of the angle to change
4060  * @angle: the angle of rotation
4061  *
4062  * Sets the rotation angle on the given axis without affecting the
4063  * rotation center point.
4064  */
4065 static inline void
4066 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4067                                            ClutterRotateAxis  axis,
4068                                            gdouble            angle)
4069 {
4070   GObject *obj = G_OBJECT (self);
4071   ClutterTransformInfo *info;
4072
4073   info = _clutter_actor_get_transform_info (self);
4074
4075   g_object_freeze_notify (obj);
4076
4077   switch (axis)
4078     {
4079     case CLUTTER_X_AXIS:
4080       info->rx_angle = angle;
4081       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4082       break;
4083
4084     case CLUTTER_Y_AXIS:
4085       info->ry_angle = angle;
4086       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4087       break;
4088
4089     case CLUTTER_Z_AXIS:
4090       info->rz_angle = angle;
4091       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4092       break;
4093     }
4094
4095   self->priv->transform_valid = FALSE;
4096
4097   g_object_thaw_notify (obj);
4098
4099   clutter_actor_queue_redraw (self);
4100 }
4101
4102 static inline void
4103 clutter_actor_set_rotation_angle (ClutterActor      *self,
4104                                   ClutterRotateAxis  axis,
4105                                   gdouble            angle)
4106 {
4107   const ClutterTransformInfo *info;
4108   const double *cur_angle_p = NULL;
4109   GParamSpec *pspec = NULL;
4110
4111   info = _clutter_actor_get_transform_info_or_defaults (self);
4112
4113   switch (axis)
4114     {
4115     case CLUTTER_X_AXIS:
4116       cur_angle_p = &info->rx_angle;
4117       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4118       break;
4119
4120     case CLUTTER_Y_AXIS:
4121       cur_angle_p = &info->ry_angle;
4122       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4123       break;
4124
4125     case CLUTTER_Z_AXIS:
4126       cur_angle_p = &info->rz_angle;
4127       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4128       break;
4129     }
4130
4131   g_assert (pspec != NULL);
4132   g_assert (cur_angle_p != NULL);
4133
4134   if (_clutter_actor_get_transition (self, pspec) == NULL)
4135     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4136   else
4137     _clutter_actor_update_transition (self, pspec, angle);
4138
4139   clutter_actor_queue_redraw (self);
4140 }
4141
4142 /*< private >
4143  * clutter_actor_set_rotation_center_internal:
4144  * @self: a #ClutterActor
4145  * @axis: the axis of the center to change
4146  * @center: the coordinates of the rotation center
4147  *
4148  * Sets the rotation center on the given axis without affecting the
4149  * rotation angle.
4150  */
4151 static inline void
4152 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4153                                             ClutterRotateAxis    axis,
4154                                             const ClutterVertex *center)
4155 {
4156   GObject *obj = G_OBJECT (self);
4157   ClutterTransformInfo *info;
4158   ClutterVertex v = { 0, 0, 0 };
4159
4160   info = _clutter_actor_get_transform_info (self);
4161
4162   if (center != NULL)
4163     v = *center;
4164
4165   g_object_freeze_notify (obj);
4166
4167   switch (axis)
4168     {
4169     case CLUTTER_X_AXIS:
4170       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4171       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4172       break;
4173
4174     case CLUTTER_Y_AXIS:
4175       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4176       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4177       break;
4178
4179     case CLUTTER_Z_AXIS:
4180       /* if the previously set rotation center was fractional, then
4181        * setting explicit coordinates will have to notify the
4182        * :rotation-center-z-gravity property as well
4183        */
4184       if (info->rz_center.is_fractional)
4185         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4186
4187       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4188       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4189       break;
4190     }
4191
4192   self->priv->transform_valid = FALSE;
4193
4194   g_object_thaw_notify (obj);
4195
4196   clutter_actor_queue_redraw (self);
4197 }
4198
4199 static void
4200 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4201                                          double factor,
4202                                          GParamSpec *pspec)
4203 {
4204   GObject *obj = G_OBJECT (self);
4205   ClutterTransformInfo *info;
4206
4207   info = _clutter_actor_get_transform_info (self);
4208
4209   if (pspec == obj_props[PROP_SCALE_X])
4210     info->scale_x = factor;
4211   else
4212     info->scale_y = factor;
4213
4214   self->priv->transform_valid = FALSE;
4215   clutter_actor_queue_redraw (self);
4216   g_object_notify_by_pspec (obj, pspec);
4217 }
4218
4219 static inline void
4220 clutter_actor_set_scale_factor (ClutterActor      *self,
4221                                 ClutterRotateAxis  axis,
4222                                 gdouble            factor)
4223 {
4224   const ClutterTransformInfo *info;
4225   const double *scale_p = NULL;
4226   GParamSpec *pspec = NULL;
4227
4228   info = _clutter_actor_get_transform_info_or_defaults (self);
4229
4230   switch (axis)
4231     {
4232     case CLUTTER_X_AXIS:
4233       pspec = obj_props[PROP_SCALE_X];
4234       scale_p = &info->scale_x;
4235       break;
4236
4237     case CLUTTER_Y_AXIS:
4238       pspec = obj_props[PROP_SCALE_Y];
4239       scale_p = &info->scale_y;
4240       break;
4241
4242     case CLUTTER_Z_AXIS:
4243       break;
4244     }
4245
4246   g_assert (pspec != NULL);
4247   g_assert (scale_p != NULL);
4248
4249   if (_clutter_actor_get_transition (self, pspec) == NULL)
4250     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4251   else
4252     _clutter_actor_update_transition (self, pspec, factor);
4253
4254   clutter_actor_queue_redraw (self);
4255 }
4256
4257 static inline void
4258 clutter_actor_set_scale_center (ClutterActor      *self,
4259                                 ClutterRotateAxis  axis,
4260                                 gfloat             coord)
4261 {
4262   GObject *obj = G_OBJECT (self);
4263   ClutterTransformInfo *info;
4264   gfloat center_x, center_y;
4265
4266   info = _clutter_actor_get_transform_info (self);
4267
4268   g_object_freeze_notify (obj);
4269
4270   /* get the current scale center coordinates */
4271   clutter_anchor_coord_get_units (self, &info->scale_center,
4272                                   &center_x,
4273                                   &center_y,
4274                                   NULL);
4275
4276   /* we need to notify this too, because setting explicit coordinates will
4277    * change the gravity as a side effect
4278    */
4279   if (info->scale_center.is_fractional)
4280     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4281
4282   switch (axis)
4283     {
4284     case CLUTTER_X_AXIS:
4285       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4286       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4287       break;
4288
4289     case CLUTTER_Y_AXIS:
4290       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4291       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4292       break;
4293
4294     default:
4295       g_assert_not_reached ();
4296     }
4297
4298   self->priv->transform_valid = FALSE;
4299
4300   clutter_actor_queue_redraw (self);
4301
4302   g_object_thaw_notify (obj);
4303 }
4304
4305 static inline void
4306 clutter_actor_set_scale_gravity (ClutterActor   *self,
4307                                  ClutterGravity  gravity)
4308 {
4309   ClutterTransformInfo *info;
4310   GObject *obj;
4311
4312   info = _clutter_actor_get_transform_info (self);
4313   obj = G_OBJECT (self);
4314
4315   if (gravity == CLUTTER_GRAVITY_NONE)
4316     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4317   else
4318     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4319
4320   self->priv->transform_valid = FALSE;
4321
4322   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4323   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4324   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4325
4326   clutter_actor_queue_redraw (self);
4327 }
4328
4329 static inline void
4330 clutter_actor_set_anchor_coord (ClutterActor      *self,
4331                                 ClutterRotateAxis  axis,
4332                                 gfloat             coord)
4333 {
4334   GObject *obj = G_OBJECT (self);
4335   ClutterTransformInfo *info;
4336   gfloat anchor_x, anchor_y;
4337
4338   info = _clutter_actor_get_transform_info (self);
4339
4340   g_object_freeze_notify (obj);
4341
4342   clutter_anchor_coord_get_units (self, &info->anchor,
4343                                   &anchor_x,
4344                                   &anchor_y,
4345                                   NULL);
4346
4347   if (info->anchor.is_fractional)
4348     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4349
4350   switch (axis)
4351     {
4352     case CLUTTER_X_AXIS:
4353       clutter_anchor_coord_set_units (&info->anchor,
4354                                       coord,
4355                                       anchor_y,
4356                                       0.0);
4357       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4358       break;
4359
4360     case CLUTTER_Y_AXIS:
4361       clutter_anchor_coord_set_units (&info->anchor,
4362                                       anchor_x,
4363                                       coord,
4364                                       0.0);
4365       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4366       break;
4367
4368     default:
4369       g_assert_not_reached ();
4370     }
4371
4372   self->priv->transform_valid = FALSE;
4373
4374   clutter_actor_queue_redraw (self);
4375
4376   g_object_thaw_notify (obj);
4377 }
4378
4379 static void
4380 clutter_actor_set_property (GObject      *object,
4381                             guint         prop_id,
4382                             const GValue *value,
4383                             GParamSpec   *pspec)
4384 {
4385   ClutterActor *actor = CLUTTER_ACTOR (object);
4386   ClutterActorPrivate *priv = actor->priv;
4387
4388   switch (prop_id)
4389     {
4390     case PROP_X:
4391       clutter_actor_set_x (actor, g_value_get_float (value));
4392       break;
4393
4394     case PROP_Y:
4395       clutter_actor_set_y (actor, g_value_get_float (value));
4396       break;
4397
4398     case PROP_POSITION:
4399       {
4400         const ClutterPoint *pos = g_value_get_boxed (value);
4401
4402         if (pos != NULL)
4403           clutter_actor_set_position (actor, pos->x, pos->y);
4404         else
4405           clutter_actor_set_fixed_position_set (actor, FALSE);
4406       }
4407       break;
4408
4409     case PROP_WIDTH:
4410       clutter_actor_set_width (actor, g_value_get_float (value));
4411       break;
4412
4413     case PROP_HEIGHT:
4414       clutter_actor_set_height (actor, g_value_get_float (value));
4415       break;
4416
4417     case PROP_SIZE:
4418       {
4419         const ClutterSize *size = g_value_get_boxed (value);
4420
4421         if (size != NULL)
4422           clutter_actor_set_size (actor, size->width, size->height);
4423         else
4424           clutter_actor_set_size (actor, -1, -1);
4425       }
4426       break;
4427
4428     case PROP_FIXED_X:
4429       clutter_actor_set_x (actor, g_value_get_float (value));
4430       break;
4431
4432     case PROP_FIXED_Y:
4433       clutter_actor_set_y (actor, g_value_get_float (value));
4434       break;
4435
4436     case PROP_FIXED_POSITION_SET:
4437       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4438       break;
4439
4440     case PROP_MIN_WIDTH:
4441       clutter_actor_set_min_width (actor, g_value_get_float (value));
4442       break;
4443
4444     case PROP_MIN_HEIGHT:
4445       clutter_actor_set_min_height (actor, g_value_get_float (value));
4446       break;
4447
4448     case PROP_NATURAL_WIDTH:
4449       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4450       break;
4451
4452     case PROP_NATURAL_HEIGHT:
4453       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4454       break;
4455
4456     case PROP_MIN_WIDTH_SET:
4457       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4458       break;
4459
4460     case PROP_MIN_HEIGHT_SET:
4461       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4462       break;
4463
4464     case PROP_NATURAL_WIDTH_SET:
4465       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4466       break;
4467
4468     case PROP_NATURAL_HEIGHT_SET:
4469       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4470       break;
4471
4472     case PROP_REQUEST_MODE:
4473       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4474       break;
4475
4476     case PROP_DEPTH:
4477       clutter_actor_set_depth (actor, g_value_get_float (value));
4478       break;
4479
4480     case PROP_OPACITY:
4481       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4482       break;
4483
4484     case PROP_OFFSCREEN_REDIRECT:
4485       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4486       break;
4487
4488     case PROP_NAME:
4489       clutter_actor_set_name (actor, g_value_get_string (value));
4490       break;
4491
4492     case PROP_VISIBLE:
4493       if (g_value_get_boolean (value) == TRUE)
4494         clutter_actor_show (actor);
4495       else
4496         clutter_actor_hide (actor);
4497       break;
4498
4499     case PROP_SCALE_X:
4500       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4501                                       g_value_get_double (value));
4502       break;
4503
4504     case PROP_SCALE_Y:
4505       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4506                                       g_value_get_double (value));
4507       break;
4508
4509     case PROP_SCALE_CENTER_X:
4510       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4511                                       g_value_get_float (value));
4512       break;
4513
4514     case PROP_SCALE_CENTER_Y:
4515       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4516                                       g_value_get_float (value));
4517       break;
4518
4519     case PROP_SCALE_GRAVITY:
4520       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4521       break;
4522
4523     case PROP_CLIP:
4524       {
4525         const ClutterGeometry *geom = g_value_get_boxed (value);
4526
4527         clutter_actor_set_clip (actor,
4528                                 geom->x, geom->y,
4529                                 geom->width, geom->height);
4530       }
4531       break;
4532
4533     case PROP_CLIP_TO_ALLOCATION:
4534       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4535       break;
4536
4537     case PROP_REACTIVE:
4538       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4539       break;
4540
4541     case PROP_ROTATION_ANGLE_X:
4542       clutter_actor_set_rotation_angle (actor,
4543                                         CLUTTER_X_AXIS,
4544                                         g_value_get_double (value));
4545       break;
4546
4547     case PROP_ROTATION_ANGLE_Y:
4548       clutter_actor_set_rotation_angle (actor,
4549                                         CLUTTER_Y_AXIS,
4550                                         g_value_get_double (value));
4551       break;
4552
4553     case PROP_ROTATION_ANGLE_Z:
4554       clutter_actor_set_rotation_angle (actor,
4555                                         CLUTTER_Z_AXIS,
4556                                         g_value_get_double (value));
4557       break;
4558
4559     case PROP_ROTATION_CENTER_X:
4560       clutter_actor_set_rotation_center_internal (actor,
4561                                                   CLUTTER_X_AXIS,
4562                                                   g_value_get_boxed (value));
4563       break;
4564
4565     case PROP_ROTATION_CENTER_Y:
4566       clutter_actor_set_rotation_center_internal (actor,
4567                                                   CLUTTER_Y_AXIS,
4568                                                   g_value_get_boxed (value));
4569       break;
4570
4571     case PROP_ROTATION_CENTER_Z:
4572       clutter_actor_set_rotation_center_internal (actor,
4573                                                   CLUTTER_Z_AXIS,
4574                                                   g_value_get_boxed (value));
4575       break;
4576
4577     case PROP_ROTATION_CENTER_Z_GRAVITY:
4578       {
4579         const ClutterTransformInfo *info;
4580
4581         info = _clutter_actor_get_transform_info_or_defaults (actor);
4582         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4583                                                    g_value_get_enum (value));
4584       }
4585       break;
4586
4587     case PROP_ANCHOR_X:
4588       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4589                                       g_value_get_float (value));
4590       break;
4591
4592     case PROP_ANCHOR_Y:
4593       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4594                                       g_value_get_float (value));
4595       break;
4596
4597     case PROP_ANCHOR_GRAVITY:
4598       clutter_actor_set_anchor_point_from_gravity (actor,
4599                                                    g_value_get_enum (value));
4600       break;
4601
4602     case PROP_SHOW_ON_SET_PARENT:
4603       priv->show_on_set_parent = g_value_get_boolean (value);
4604       break;
4605
4606     case PROP_TEXT_DIRECTION:
4607       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4608       break;
4609
4610     case PROP_ACTIONS:
4611       clutter_actor_add_action (actor, g_value_get_object (value));
4612       break;
4613
4614     case PROP_CONSTRAINTS:
4615       clutter_actor_add_constraint (actor, g_value_get_object (value));
4616       break;
4617
4618     case PROP_EFFECT:
4619       clutter_actor_add_effect (actor, g_value_get_object (value));
4620       break;
4621
4622     case PROP_LAYOUT_MANAGER:
4623       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4624       break;
4625
4626     case PROP_X_EXPAND:
4627       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4628       break;
4629
4630     case PROP_Y_EXPAND:
4631       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4632       break;
4633
4634     case PROP_X_ALIGN:
4635       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4636       break;
4637
4638     case PROP_Y_ALIGN:
4639       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4640       break;
4641
4642     case PROP_MARGIN_TOP:
4643       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4644       break;
4645
4646     case PROP_MARGIN_BOTTOM:
4647       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4648       break;
4649
4650     case PROP_MARGIN_LEFT:
4651       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4652       break;
4653
4654     case PROP_MARGIN_RIGHT:
4655       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4656       break;
4657
4658     case PROP_BACKGROUND_COLOR:
4659       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4660       break;
4661
4662     case PROP_CONTENT:
4663       clutter_actor_set_content (actor, g_value_get_object (value));
4664       break;
4665
4666     case PROP_CONTENT_GRAVITY:
4667       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4668       break;
4669
4670     case PROP_MINIFICATION_FILTER:
4671       clutter_actor_set_content_scaling_filters (actor,
4672                                                  g_value_get_enum (value),
4673                                                  actor->priv->mag_filter);
4674       break;
4675
4676     case PROP_MAGNIFICATION_FILTER:
4677       clutter_actor_set_content_scaling_filters (actor,
4678                                                  actor->priv->min_filter,
4679                                                  g_value_get_enum (value));
4680       break;
4681
4682     default:
4683       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4684       break;
4685     }
4686 }
4687
4688 static void
4689 clutter_actor_get_property (GObject    *object,
4690                             guint       prop_id,
4691                             GValue     *value,
4692                             GParamSpec *pspec)
4693 {
4694   ClutterActor *actor = CLUTTER_ACTOR (object);
4695   ClutterActorPrivate *priv = actor->priv;
4696
4697   switch (prop_id)
4698     {
4699     case PROP_X:
4700       g_value_set_float (value, clutter_actor_get_x (actor));
4701       break;
4702
4703     case PROP_Y:
4704       g_value_set_float (value, clutter_actor_get_y (actor));
4705       break;
4706
4707     case PROP_POSITION:
4708       {
4709         ClutterPoint position;
4710
4711         clutter_point_init (&position,
4712                             clutter_actor_get_x (actor),
4713                             clutter_actor_get_y (actor));
4714         g_value_set_boxed (value, &position);
4715       }
4716       break;
4717
4718     case PROP_WIDTH:
4719       g_value_set_float (value, clutter_actor_get_width (actor));
4720       break;
4721
4722     case PROP_HEIGHT:
4723       g_value_set_float (value, clutter_actor_get_height (actor));
4724       break;
4725
4726     case PROP_SIZE:
4727       {
4728         ClutterSize size;
4729
4730         clutter_size_init (&size,
4731                            clutter_actor_get_width (actor),
4732                            clutter_actor_get_height (actor));
4733         g_value_set_boxed (value, &size);
4734       }
4735       break;
4736
4737     case PROP_FIXED_X:
4738       {
4739         const ClutterLayoutInfo *info;
4740
4741         info = _clutter_actor_get_layout_info_or_defaults (actor);
4742         g_value_set_float (value, info->fixed_pos.x);
4743       }
4744       break;
4745
4746     case PROP_FIXED_Y:
4747       {
4748         const ClutterLayoutInfo *info;
4749
4750         info = _clutter_actor_get_layout_info_or_defaults (actor);
4751         g_value_set_float (value, info->fixed_pos.y);
4752       }
4753       break;
4754
4755     case PROP_FIXED_POSITION_SET:
4756       g_value_set_boolean (value, priv->position_set);
4757       break;
4758
4759     case PROP_MIN_WIDTH:
4760       {
4761         const ClutterLayoutInfo *info;
4762
4763         info = _clutter_actor_get_layout_info_or_defaults (actor);
4764         g_value_set_float (value, info->minimum.width);
4765       }
4766       break;
4767
4768     case PROP_MIN_HEIGHT:
4769       {
4770         const ClutterLayoutInfo *info;
4771
4772         info = _clutter_actor_get_layout_info_or_defaults (actor);
4773         g_value_set_float (value, info->minimum.height);
4774       }
4775       break;
4776
4777     case PROP_NATURAL_WIDTH:
4778       {
4779         const ClutterLayoutInfo *info;
4780
4781         info = _clutter_actor_get_layout_info_or_defaults (actor);
4782         g_value_set_float (value, info->natural.width);
4783       }
4784       break;
4785
4786     case PROP_NATURAL_HEIGHT:
4787       {
4788         const ClutterLayoutInfo *info;
4789
4790         info = _clutter_actor_get_layout_info_or_defaults (actor);
4791         g_value_set_float (value, info->natural.height);
4792       }
4793       break;
4794
4795     case PROP_MIN_WIDTH_SET:
4796       g_value_set_boolean (value, priv->min_width_set);
4797       break;
4798
4799     case PROP_MIN_HEIGHT_SET:
4800       g_value_set_boolean (value, priv->min_height_set);
4801       break;
4802
4803     case PROP_NATURAL_WIDTH_SET:
4804       g_value_set_boolean (value, priv->natural_width_set);
4805       break;
4806
4807     case PROP_NATURAL_HEIGHT_SET:
4808       g_value_set_boolean (value, priv->natural_height_set);
4809       break;
4810
4811     case PROP_REQUEST_MODE:
4812       g_value_set_enum (value, priv->request_mode);
4813       break;
4814
4815     case PROP_ALLOCATION:
4816       g_value_set_boxed (value, &priv->allocation);
4817       break;
4818
4819     case PROP_DEPTH:
4820       g_value_set_float (value, clutter_actor_get_depth (actor));
4821       break;
4822
4823     case PROP_OPACITY:
4824       g_value_set_uint (value, priv->opacity);
4825       break;
4826
4827     case PROP_OFFSCREEN_REDIRECT:
4828       g_value_set_enum (value, priv->offscreen_redirect);
4829       break;
4830
4831     case PROP_NAME:
4832       g_value_set_string (value, priv->name);
4833       break;
4834
4835     case PROP_VISIBLE:
4836       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4837       break;
4838
4839     case PROP_MAPPED:
4840       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4841       break;
4842
4843     case PROP_REALIZED:
4844       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4845       break;
4846
4847     case PROP_HAS_CLIP:
4848       g_value_set_boolean (value, priv->has_clip);
4849       break;
4850
4851     case PROP_CLIP:
4852       {
4853         ClutterGeometry clip;
4854
4855         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4856         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4857         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4858         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4859
4860         g_value_set_boxed (value, &clip);
4861       }
4862       break;
4863
4864     case PROP_CLIP_TO_ALLOCATION:
4865       g_value_set_boolean (value, priv->clip_to_allocation);
4866       break;
4867
4868     case PROP_SCALE_X:
4869       {
4870         const ClutterTransformInfo *info;
4871
4872         info = _clutter_actor_get_transform_info_or_defaults (actor);
4873         g_value_set_double (value, info->scale_x);
4874       }
4875       break;
4876
4877     case PROP_SCALE_Y:
4878       {
4879         const ClutterTransformInfo *info;
4880
4881         info = _clutter_actor_get_transform_info_or_defaults (actor);
4882         g_value_set_double (value, info->scale_y);
4883       }
4884       break;
4885
4886     case PROP_SCALE_CENTER_X:
4887       {
4888         gfloat center;
4889
4890         clutter_actor_get_scale_center (actor, &center, NULL);
4891
4892         g_value_set_float (value, center);
4893       }
4894       break;
4895
4896     case PROP_SCALE_CENTER_Y:
4897       {
4898         gfloat center;
4899
4900         clutter_actor_get_scale_center (actor, NULL, &center);
4901
4902         g_value_set_float (value, center);
4903       }
4904       break;
4905
4906     case PROP_SCALE_GRAVITY:
4907       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4908       break;
4909
4910     case PROP_REACTIVE:
4911       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4912       break;
4913
4914     case PROP_ROTATION_ANGLE_X:
4915       {
4916         const ClutterTransformInfo *info;
4917
4918         info = _clutter_actor_get_transform_info_or_defaults (actor);
4919         g_value_set_double (value, info->rx_angle);
4920       }
4921       break;
4922
4923     case PROP_ROTATION_ANGLE_Y:
4924       {
4925         const ClutterTransformInfo *info;
4926
4927         info = _clutter_actor_get_transform_info_or_defaults (actor);
4928         g_value_set_double (value, info->ry_angle);
4929       }
4930       break;
4931
4932     case PROP_ROTATION_ANGLE_Z:
4933       {
4934         const ClutterTransformInfo *info;
4935
4936         info = _clutter_actor_get_transform_info_or_defaults (actor);
4937         g_value_set_double (value, info->rz_angle);
4938       }
4939       break;
4940
4941     case PROP_ROTATION_CENTER_X:
4942       {
4943         ClutterVertex center;
4944
4945         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4946                                     &center.x,
4947                                     &center.y,
4948                                     &center.z);
4949
4950         g_value_set_boxed (value, &center);
4951       }
4952       break;
4953
4954     case PROP_ROTATION_CENTER_Y:
4955       {
4956         ClutterVertex center;
4957
4958         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4959                                     &center.x,
4960                                     &center.y,
4961                                     &center.z);
4962
4963         g_value_set_boxed (value, &center);
4964       }
4965       break;
4966
4967     case PROP_ROTATION_CENTER_Z:
4968       {
4969         ClutterVertex center;
4970
4971         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4972                                     &center.x,
4973                                     &center.y,
4974                                     &center.z);
4975
4976         g_value_set_boxed (value, &center);
4977       }
4978       break;
4979
4980     case PROP_ROTATION_CENTER_Z_GRAVITY:
4981       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4982       break;
4983
4984     case PROP_ANCHOR_X:
4985       {
4986         const ClutterTransformInfo *info;
4987         gfloat anchor_x;
4988
4989         info = _clutter_actor_get_transform_info_or_defaults (actor);
4990         clutter_anchor_coord_get_units (actor, &info->anchor,
4991                                         &anchor_x,
4992                                         NULL,
4993                                         NULL);
4994         g_value_set_float (value, anchor_x);
4995       }
4996       break;
4997
4998     case PROP_ANCHOR_Y:
4999       {
5000         const ClutterTransformInfo *info;
5001         gfloat anchor_y;
5002
5003         info = _clutter_actor_get_transform_info_or_defaults (actor);
5004         clutter_anchor_coord_get_units (actor, &info->anchor,
5005                                         NULL,
5006                                         &anchor_y,
5007                                         NULL);
5008         g_value_set_float (value, anchor_y);
5009       }
5010       break;
5011
5012     case PROP_ANCHOR_GRAVITY:
5013       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5014       break;
5015
5016     case PROP_SHOW_ON_SET_PARENT:
5017       g_value_set_boolean (value, priv->show_on_set_parent);
5018       break;
5019
5020     case PROP_TEXT_DIRECTION:
5021       g_value_set_enum (value, priv->text_direction);
5022       break;
5023
5024     case PROP_HAS_POINTER:
5025       g_value_set_boolean (value, priv->has_pointer);
5026       break;
5027
5028     case PROP_LAYOUT_MANAGER:
5029       g_value_set_object (value, priv->layout_manager);
5030       break;
5031
5032     case PROP_X_EXPAND:
5033       {
5034         const ClutterLayoutInfo *info;
5035
5036         info = _clutter_actor_get_layout_info_or_defaults (actor);
5037         g_value_set_boolean (value, info->x_expand);
5038       }
5039       break;
5040
5041     case PROP_Y_EXPAND:
5042       {
5043         const ClutterLayoutInfo *info;
5044
5045         info = _clutter_actor_get_layout_info_or_defaults (actor);
5046         g_value_set_boolean (value, info->y_expand);
5047       }
5048       break;
5049
5050     case PROP_X_ALIGN:
5051       {
5052         const ClutterLayoutInfo *info;
5053
5054         info = _clutter_actor_get_layout_info_or_defaults (actor);
5055         g_value_set_enum (value, info->x_align);
5056       }
5057       break;
5058
5059     case PROP_Y_ALIGN:
5060       {
5061         const ClutterLayoutInfo *info;
5062
5063         info = _clutter_actor_get_layout_info_or_defaults (actor);
5064         g_value_set_enum (value, info->y_align);
5065       }
5066       break;
5067
5068     case PROP_MARGIN_TOP:
5069       {
5070         const ClutterLayoutInfo *info;
5071
5072         info = _clutter_actor_get_layout_info_or_defaults (actor);
5073         g_value_set_float (value, info->margin.top);
5074       }
5075       break;
5076
5077     case PROP_MARGIN_BOTTOM:
5078       {
5079         const ClutterLayoutInfo *info;
5080
5081         info = _clutter_actor_get_layout_info_or_defaults (actor);
5082         g_value_set_float (value, info->margin.bottom);
5083       }
5084       break;
5085
5086     case PROP_MARGIN_LEFT:
5087       {
5088         const ClutterLayoutInfo *info;
5089
5090         info = _clutter_actor_get_layout_info_or_defaults (actor);
5091         g_value_set_float (value, info->margin.left);
5092       }
5093       break;
5094
5095     case PROP_MARGIN_RIGHT:
5096       {
5097         const ClutterLayoutInfo *info;
5098
5099         info = _clutter_actor_get_layout_info_or_defaults (actor);
5100         g_value_set_float (value, info->margin.right);
5101       }
5102       break;
5103
5104     case PROP_BACKGROUND_COLOR_SET:
5105       g_value_set_boolean (value, priv->bg_color_set);
5106       break;
5107
5108     case PROP_BACKGROUND_COLOR:
5109       g_value_set_boxed (value, &priv->bg_color);
5110       break;
5111
5112     case PROP_FIRST_CHILD:
5113       g_value_set_object (value, priv->first_child);
5114       break;
5115
5116     case PROP_LAST_CHILD:
5117       g_value_set_object (value, priv->last_child);
5118       break;
5119
5120     case PROP_CONTENT:
5121       g_value_set_object (value, priv->content);
5122       break;
5123
5124     case PROP_CONTENT_GRAVITY:
5125       g_value_set_enum (value, priv->content_gravity);
5126       break;
5127
5128     case PROP_CONTENT_BOX:
5129       {
5130         ClutterActorBox box = { 0, };
5131
5132         clutter_actor_get_content_box (actor, &box);
5133         g_value_set_boxed (value, &box);
5134       }
5135       break;
5136
5137     case PROP_MINIFICATION_FILTER:
5138       g_value_set_enum (value, priv->min_filter);
5139       break;
5140
5141     case PROP_MAGNIFICATION_FILTER:
5142       g_value_set_enum (value, priv->mag_filter);
5143       break;
5144
5145     default:
5146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5147       break;
5148     }
5149 }
5150
5151 static void
5152 clutter_actor_dispose (GObject *object)
5153 {
5154   ClutterActor *self = CLUTTER_ACTOR (object);
5155   ClutterActorPrivate *priv = self->priv;
5156
5157   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5158                 priv->id,
5159                 g_type_name (G_OBJECT_TYPE (self)),
5160                 object->ref_count);
5161
5162   g_signal_emit (self, actor_signals[DESTROY], 0);
5163
5164   /* avoid recursing when called from clutter_actor_destroy() */
5165   if (priv->parent != NULL)
5166     {
5167       ClutterActor *parent = priv->parent;
5168
5169       /* go through the Container implementation unless this
5170        * is an internal child and has been marked as such.
5171        *
5172        * removing the actor from its parent will reset the
5173        * realized and mapped states.
5174        */
5175       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5176         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5177       else
5178         clutter_actor_remove_child_internal (parent, self,
5179                                              REMOVE_CHILD_LEGACY_FLAGS);
5180     }
5181
5182   /* parent must be gone at this point */
5183   g_assert (priv->parent == NULL);
5184
5185   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5186     {
5187       /* can't be mapped or realized with no parent */
5188       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5189       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5190     }
5191
5192   g_clear_object (&priv->pango_context);
5193   g_clear_object (&priv->actions);
5194   g_clear_object (&priv->constraints);
5195   g_clear_object (&priv->effects);
5196   g_clear_object (&priv->flatten_effect);
5197
5198   if (priv->layout_manager != NULL)
5199     {
5200       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5201       g_clear_object (&priv->layout_manager);
5202     }
5203
5204   if (priv->content != NULL)
5205     {
5206       _clutter_content_detached (priv->content, self);
5207       g_clear_object (&priv->content);
5208     }
5209
5210   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5211 }
5212
5213 static void
5214 clutter_actor_finalize (GObject *object)
5215 {
5216   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5217
5218   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5219                 priv->name != NULL ? priv->name : "<none>",
5220                 priv->id,
5221                 g_type_name (G_OBJECT_TYPE (object)));
5222
5223   _clutter_context_release_id (priv->id);
5224
5225   g_free (priv->name);
5226
5227   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5228 }
5229
5230
5231 /**
5232  * clutter_actor_get_accessible:
5233  * @self: a #ClutterActor
5234  *
5235  * Returns the accessible object that describes the actor to an
5236  * assistive technology.
5237  *
5238  * If no class-specific #AtkObject implementation is available for the
5239  * actor instance in question, it will inherit an #AtkObject
5240  * implementation from the first ancestor class for which such an
5241  * implementation is defined.
5242  *
5243  * The documentation of the <ulink
5244  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5245  * library contains more information about accessible objects and
5246  * their uses.
5247  *
5248  * Returns: (transfer none): the #AtkObject associated with @actor
5249  */
5250 AtkObject *
5251 clutter_actor_get_accessible (ClutterActor *self)
5252 {
5253   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5254
5255   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5256 }
5257
5258 static AtkObject *
5259 clutter_actor_real_get_accessible (ClutterActor *actor)
5260 {
5261   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5262 }
5263
5264 static AtkObject *
5265 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5266 {
5267   AtkObject *accessible;
5268
5269   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5270   if (accessible != NULL)
5271     g_object_ref (accessible);
5272
5273   return accessible;
5274 }
5275
5276 static void
5277 atk_implementor_iface_init (AtkImplementorIface *iface)
5278 {
5279   iface->ref_accessible = _clutter_actor_ref_accessible;
5280 }
5281
5282 static gboolean
5283 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5284                                            ClutterPaintVolume *volume)
5285 {
5286   ClutterActorPrivate *priv = self->priv;
5287   gboolean res = TRUE;
5288
5289   /* we start from the allocation */
5290   clutter_paint_volume_set_width (volume,
5291                                   priv->allocation.x2 - priv->allocation.x1);
5292   clutter_paint_volume_set_height (volume,
5293                                    priv->allocation.y2 - priv->allocation.y1);
5294
5295   /* if the actor has a clip set then we have a pretty definite
5296    * size for the paint volume: the actor cannot possibly paint
5297    * outside the clip region.
5298    */
5299   if (priv->clip_to_allocation)
5300     {
5301       /* the allocation has already been set, so we just flip the
5302        * return value
5303        */
5304       res = TRUE;
5305     }
5306   else
5307     {
5308       ClutterActor *child;
5309
5310       if (priv->has_clip &&
5311           priv->clip.width >= 0 &&
5312           priv->clip.height >= 0)
5313         {
5314           ClutterVertex origin;
5315
5316           origin.x = priv->clip.x;
5317           origin.y = priv->clip.y;
5318           origin.z = 0;
5319
5320           clutter_paint_volume_set_origin (volume, &origin);
5321           clutter_paint_volume_set_width (volume, priv->clip.width);
5322           clutter_paint_volume_set_height (volume, priv->clip.height);
5323
5324           res = TRUE;
5325         }
5326
5327       /* if we don't have children we just bail out here... */
5328       if (priv->n_children == 0)
5329         return res;
5330
5331       /* ...but if we have children then we ask for their paint volume in
5332        * our coordinates. if any of our children replies that it doesn't
5333        * have a paint volume, we bail out
5334        */
5335       for (child = priv->first_child;
5336            child != NULL;
5337            child = child->priv->next_sibling)
5338         {
5339           const ClutterPaintVolume *child_volume;
5340
5341           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5342             continue;
5343
5344           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5345           if (child_volume == NULL)
5346             {
5347               res = FALSE;
5348               break;
5349             }
5350
5351           clutter_paint_volume_union (volume, child_volume);
5352           res = TRUE;
5353         }
5354     }
5355
5356   return res;
5357
5358 }
5359
5360 static gboolean
5361 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5362                                      ClutterPaintVolume *volume)
5363 {
5364   ClutterActorClass *klass;
5365   gboolean res;
5366
5367   klass = CLUTTER_ACTOR_GET_CLASS (self);
5368
5369   /* XXX - this thoroughly sucks, but we don't want to penalize users
5370    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5371    * redraw. This should go away in 2.0.
5372    */
5373   if (klass->paint == clutter_actor_real_paint &&
5374       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5375     {
5376       res = TRUE;
5377     }
5378   else
5379     {
5380       /* this is the default return value: we cannot know if a class
5381        * is going to paint outside its allocation, so we take the
5382        * conservative approach.
5383        */
5384       res = FALSE;
5385     }
5386
5387   /* update_default_paint_volume() should only fail if one of the children
5388    * reported an invalid, or no, paint volume
5389    */
5390   if (!clutter_actor_update_default_paint_volume (self, volume))
5391     return FALSE;
5392
5393   return res;
5394 }
5395
5396 /**
5397  * clutter_actor_get_default_paint_volume:
5398  * @self: a #ClutterActor
5399  *
5400  * Retrieves the default paint volume for @self.
5401  *
5402  * This function provides the same #ClutterPaintVolume that would be
5403  * computed by the default implementation inside #ClutterActor of the
5404  * #ClutterActorClass.get_paint_volume() virtual function.
5405  *
5406  * This function should only be used by #ClutterActor subclasses that
5407  * cannot chain up to the parent implementation when computing their
5408  * paint volume.
5409  *
5410  * Return value: (transfer none): a pointer to the default
5411  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5412  *   the actor could not compute a valid paint volume. The returned value
5413  *   is not guaranteed to be stable across multiple frames, so if you
5414  *   want to retain it, you will need to copy it using
5415  *   clutter_paint_volume_copy().
5416  *
5417  * Since: 1.10
5418  */
5419 const ClutterPaintVolume *
5420 clutter_actor_get_default_paint_volume (ClutterActor *self)
5421 {
5422   ClutterPaintVolume volume;
5423   ClutterPaintVolume *res;
5424
5425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5426
5427   res = NULL;
5428   _clutter_paint_volume_init_static (&volume, self);
5429   if (clutter_actor_update_default_paint_volume (self, &volume))
5430     {
5431       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5432
5433       if (stage != NULL)
5434         {
5435           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5436           _clutter_paint_volume_copy_static (&volume, res);
5437         }
5438     }
5439
5440   clutter_paint_volume_free (&volume);
5441
5442   return res;
5443 }
5444
5445 static gboolean
5446 clutter_actor_real_has_overlaps (ClutterActor *self)
5447 {
5448   /* By default we'll assume that all actors need an offscreen redirect to get
5449    * the correct opacity. Actors such as ClutterTexture that would never need
5450    * an offscreen redirect can override this to return FALSE. */
5451   return TRUE;
5452 }
5453
5454 static void
5455 clutter_actor_real_destroy (ClutterActor *actor)
5456 {
5457   ClutterActorIter iter;
5458
5459   g_object_freeze_notify (G_OBJECT (actor));
5460
5461   clutter_actor_iter_init (&iter, actor);
5462   while (clutter_actor_iter_next (&iter, NULL))
5463     clutter_actor_iter_destroy (&iter);
5464
5465   g_object_thaw_notify (G_OBJECT (actor));
5466 }
5467
5468 static GObject *
5469 clutter_actor_constructor (GType gtype,
5470                            guint n_props,
5471                            GObjectConstructParam *props)
5472 {
5473   GObjectClass *gobject_class;
5474   ClutterActor *self;
5475   GObject *retval;
5476
5477   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5478   retval = gobject_class->constructor (gtype, n_props, props);
5479   self = CLUTTER_ACTOR (retval);
5480
5481   if (self->priv->layout_manager == NULL)
5482     {
5483       ClutterLayoutManager *default_layout;
5484
5485       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5486
5487       default_layout = clutter_fixed_layout_new ();
5488       clutter_actor_set_layout_manager (self, default_layout);
5489     }
5490
5491   return retval;
5492 }
5493
5494 static void
5495 clutter_actor_class_init (ClutterActorClass *klass)
5496 {
5497   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5498
5499   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5500   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5501   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5502   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5503
5504   object_class->constructor = clutter_actor_constructor;
5505   object_class->set_property = clutter_actor_set_property;
5506   object_class->get_property = clutter_actor_get_property;
5507   object_class->dispose = clutter_actor_dispose;
5508   object_class->finalize = clutter_actor_finalize;
5509
5510   klass->show = clutter_actor_real_show;
5511   klass->show_all = clutter_actor_show;
5512   klass->hide = clutter_actor_real_hide;
5513   klass->hide_all = clutter_actor_hide;
5514   klass->map = clutter_actor_real_map;
5515   klass->unmap = clutter_actor_real_unmap;
5516   klass->unrealize = clutter_actor_real_unrealize;
5517   klass->pick = clutter_actor_real_pick;
5518   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5519   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5520   klass->allocate = clutter_actor_real_allocate;
5521   klass->queue_redraw = clutter_actor_real_queue_redraw;
5522   klass->queue_relayout = clutter_actor_real_queue_relayout;
5523   klass->apply_transform = clutter_actor_real_apply_transform;
5524   klass->get_accessible = clutter_actor_real_get_accessible;
5525   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5526   klass->has_overlaps = clutter_actor_real_has_overlaps;
5527   klass->paint = clutter_actor_real_paint;
5528   klass->destroy = clutter_actor_real_destroy;
5529
5530   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5531
5532   /**
5533    * ClutterActor:x:
5534    *
5535    * X coordinate of the actor in pixels. If written, forces a fixed
5536    * position for the actor. If read, returns the fixed position if any,
5537    * otherwise the allocation if available, otherwise 0.
5538    *
5539    * The #ClutterActor:x property is animatable.
5540    */
5541   obj_props[PROP_X] =
5542     g_param_spec_float ("x",
5543                         P_("X coordinate"),
5544                         P_("X coordinate of the actor"),
5545                         -G_MAXFLOAT, G_MAXFLOAT,
5546                         0.0,
5547                         G_PARAM_READWRITE |
5548                         G_PARAM_STATIC_STRINGS |
5549                         CLUTTER_PARAM_ANIMATABLE);
5550
5551   /**
5552    * ClutterActor:y:
5553    *
5554    * Y coordinate of the actor in pixels. If written, forces a fixed
5555    * position for the actor.  If read, returns the fixed position if
5556    * any, otherwise the allocation if available, otherwise 0.
5557    *
5558    * The #ClutterActor:y property is animatable.
5559    */
5560   obj_props[PROP_Y] =
5561     g_param_spec_float ("y",
5562                         P_("Y coordinate"),
5563                         P_("Y coordinate of the actor"),
5564                         -G_MAXFLOAT, G_MAXFLOAT,
5565                         0.0,
5566                         G_PARAM_READWRITE |
5567                         G_PARAM_STATIC_STRINGS |
5568                         CLUTTER_PARAM_ANIMATABLE);
5569
5570   /**
5571    * ClutterActor:position:
5572    *
5573    * The position of the origin of the actor.
5574    *
5575    * This property is a shorthand for setting and getting the
5576    * #ClutterActor:x and #ClutterActor:y properties at the same
5577    * time.
5578    *
5579    * The #ClutterActor:position property is animatable.
5580    *
5581    * Since: 1.12
5582    */
5583   obj_props[PROP_POSITION] =
5584     g_param_spec_boxed ("position",
5585                         P_("Position"),
5586                         P_("The position of the origin of the actor"),
5587                         CLUTTER_TYPE_POINT,
5588                         G_PARAM_READWRITE |
5589                         G_PARAM_STATIC_STRINGS |
5590                         CLUTTER_PARAM_ANIMATABLE);
5591
5592   /**
5593    * ClutterActor:width:
5594    *
5595    * Width of the actor (in pixels). If written, forces the minimum and
5596    * natural size request of the actor to the given width. If read, returns
5597    * the allocated width if available, otherwise the width request.
5598    *
5599    * The #ClutterActor:width property is animatable.
5600    */
5601   obj_props[PROP_WIDTH] =
5602     g_param_spec_float ("width",
5603                         P_("Width"),
5604                         P_("Width of the actor"),
5605                         0.0, G_MAXFLOAT,
5606                         0.0,
5607                         G_PARAM_READWRITE |
5608                         G_PARAM_STATIC_STRINGS |
5609                         CLUTTER_PARAM_ANIMATABLE);
5610
5611   /**
5612    * ClutterActor:height:
5613    *
5614    * Height of the actor (in pixels).  If written, forces the minimum and
5615    * natural size request of the actor to the given height. If read, returns
5616    * the allocated height if available, otherwise the height request.
5617    *
5618    * The #ClutterActor:height property is animatable.
5619    */
5620   obj_props[PROP_HEIGHT] =
5621     g_param_spec_float ("height",
5622                         P_("Height"),
5623                         P_("Height of the actor"),
5624                         0.0, G_MAXFLOAT,
5625                         0.0,
5626                         G_PARAM_READWRITE |
5627                         G_PARAM_STATIC_STRINGS |
5628                         CLUTTER_PARAM_ANIMATABLE);
5629
5630   /**
5631    * ClutterActor:size:
5632    *
5633    * The size of the actor.
5634    *
5635    * This property is a shorthand for setting and getting the
5636    * #ClutterActor:width and #ClutterActor:height at the same time.
5637    *
5638    * The #ClutterActor:size property is animatable.
5639    *
5640    * Since: 1.12
5641    */
5642   obj_props[PROP_SIZE] =
5643     g_param_spec_boxed ("size",
5644                         P_("Size"),
5645                         P_("The size of the actor"),
5646                         CLUTTER_TYPE_SIZE,
5647                         G_PARAM_READWRITE |
5648                         G_PARAM_STATIC_STRINGS |
5649                         CLUTTER_PARAM_ANIMATABLE);
5650
5651   /**
5652    * ClutterActor:fixed-x:
5653    *
5654    * The fixed X position of the actor in pixels.
5655    *
5656    * Writing this property sets #ClutterActor:fixed-position-set
5657    * property as well, as a side effect
5658    *
5659    * Since: 0.8
5660    */
5661   obj_props[PROP_FIXED_X] =
5662     g_param_spec_float ("fixed-x",
5663                         P_("Fixed X"),
5664                         P_("Forced X position of the actor"),
5665                         -G_MAXFLOAT, G_MAXFLOAT,
5666                         0.0,
5667                         CLUTTER_PARAM_READWRITE);
5668
5669   /**
5670    * ClutterActor:fixed-y:
5671    *
5672    * The fixed Y position of the actor in pixels.
5673    *
5674    * Writing this property sets the #ClutterActor:fixed-position-set
5675    * property as well, as a side effect
5676    *
5677    * Since: 0.8
5678    */
5679   obj_props[PROP_FIXED_Y] =
5680     g_param_spec_float ("fixed-y",
5681                         P_("Fixed Y"),
5682                         P_("Forced Y position of the actor"),
5683                         -G_MAXFLOAT, G_MAXFLOAT,
5684                         0,
5685                         CLUTTER_PARAM_READWRITE);
5686
5687   /**
5688    * ClutterActor:fixed-position-set:
5689    *
5690    * This flag controls whether the #ClutterActor:fixed-x and
5691    * #ClutterActor:fixed-y properties are used
5692    *
5693    * Since: 0.8
5694    */
5695   obj_props[PROP_FIXED_POSITION_SET] =
5696     g_param_spec_boolean ("fixed-position-set",
5697                           P_("Fixed position set"),
5698                           P_("Whether to use fixed positioning for the actor"),
5699                           FALSE,
5700                           CLUTTER_PARAM_READWRITE);
5701
5702   /**
5703    * ClutterActor:min-width:
5704    *
5705    * A forced minimum width request for the actor, in pixels
5706    *
5707    * Writing this property sets the #ClutterActor:min-width-set property
5708    * as well, as a side effect.
5709    *
5710    *This property overrides the usual width request of the actor.
5711    *
5712    * Since: 0.8
5713    */
5714   obj_props[PROP_MIN_WIDTH] =
5715     g_param_spec_float ("min-width",
5716                         P_("Min Width"),
5717                         P_("Forced minimum width request for the actor"),
5718                         0.0, G_MAXFLOAT,
5719                         0.0,
5720                         CLUTTER_PARAM_READWRITE);
5721
5722   /**
5723    * ClutterActor:min-height:
5724    *
5725    * A forced minimum height request for the actor, in pixels
5726    *
5727    * Writing this property sets the #ClutterActor:min-height-set property
5728    * as well, as a side effect. This property overrides the usual height
5729    * request of the actor.
5730    *
5731    * Since: 0.8
5732    */
5733   obj_props[PROP_MIN_HEIGHT] =
5734     g_param_spec_float ("min-height",
5735                         P_("Min Height"),
5736                         P_("Forced minimum height request for the actor"),
5737                         0.0, G_MAXFLOAT,
5738                         0.0,
5739                         CLUTTER_PARAM_READWRITE);
5740
5741   /**
5742    * ClutterActor:natural-width:
5743    *
5744    * A forced natural width request for the actor, in pixels
5745    *
5746    * Writing this property sets the #ClutterActor:natural-width-set
5747    * property as well, as a side effect. This property overrides the
5748    * usual width request of the actor
5749    *
5750    * Since: 0.8
5751    */
5752   obj_props[PROP_NATURAL_WIDTH] =
5753     g_param_spec_float ("natural-width",
5754                         P_("Natural Width"),
5755                         P_("Forced natural width request for the actor"),
5756                         0.0, G_MAXFLOAT,
5757                         0.0,
5758                         CLUTTER_PARAM_READWRITE);
5759
5760   /**
5761    * ClutterActor:natural-height:
5762    *
5763    * A forced natural height request for the actor, in pixels
5764    *
5765    * Writing this property sets the #ClutterActor:natural-height-set
5766    * property as well, as a side effect. This property overrides the
5767    * usual height request of the actor
5768    *
5769    * Since: 0.8
5770    */
5771   obj_props[PROP_NATURAL_HEIGHT] =
5772     g_param_spec_float ("natural-height",
5773                         P_("Natural Height"),
5774                         P_("Forced natural height request for the actor"),
5775                         0.0, G_MAXFLOAT,
5776                         0.0,
5777                         CLUTTER_PARAM_READWRITE);
5778
5779   /**
5780    * ClutterActor:min-width-set:
5781    *
5782    * This flag controls whether the #ClutterActor:min-width property
5783    * is used
5784    *
5785    * Since: 0.8
5786    */
5787   obj_props[PROP_MIN_WIDTH_SET] =
5788     g_param_spec_boolean ("min-width-set",
5789                           P_("Minimum width set"),
5790                           P_("Whether to use the min-width property"),
5791                           FALSE,
5792                           CLUTTER_PARAM_READWRITE);
5793
5794   /**
5795    * ClutterActor:min-height-set:
5796    *
5797    * This flag controls whether the #ClutterActor:min-height property
5798    * is used
5799    *
5800    * Since: 0.8
5801    */
5802   obj_props[PROP_MIN_HEIGHT_SET] =
5803     g_param_spec_boolean ("min-height-set",
5804                           P_("Minimum height set"),
5805                           P_("Whether to use the min-height property"),
5806                           FALSE,
5807                           CLUTTER_PARAM_READWRITE);
5808
5809   /**
5810    * ClutterActor:natural-width-set:
5811    *
5812    * This flag controls whether the #ClutterActor:natural-width property
5813    * is used
5814    *
5815    * Since: 0.8
5816    */
5817   obj_props[PROP_NATURAL_WIDTH_SET] =
5818     g_param_spec_boolean ("natural-width-set",
5819                           P_("Natural width set"),
5820                           P_("Whether to use the natural-width property"),
5821                           FALSE,
5822                           CLUTTER_PARAM_READWRITE);
5823
5824   /**
5825    * ClutterActor:natural-height-set:
5826    *
5827    * This flag controls whether the #ClutterActor:natural-height property
5828    * is used
5829    *
5830    * Since: 0.8
5831    */
5832   obj_props[PROP_NATURAL_HEIGHT_SET] =
5833     g_param_spec_boolean ("natural-height-set",
5834                           P_("Natural height set"),
5835                           P_("Whether to use the natural-height property"),
5836                           FALSE,
5837                           CLUTTER_PARAM_READWRITE);
5838
5839   /**
5840    * ClutterActor:allocation:
5841    *
5842    * The allocation for the actor, in pixels
5843    *
5844    * This is property is read-only, but you might monitor it to know when an
5845    * actor moves or resizes
5846    *
5847    * Since: 0.8
5848    */
5849   obj_props[PROP_ALLOCATION] =
5850     g_param_spec_boxed ("allocation",
5851                         P_("Allocation"),
5852                         P_("The actor's allocation"),
5853                         CLUTTER_TYPE_ACTOR_BOX,
5854                         CLUTTER_PARAM_READABLE);
5855
5856   /**
5857    * ClutterActor:request-mode:
5858    *
5859    * Request mode for the #ClutterActor. The request mode determines the
5860    * type of geometry management used by the actor, either height for width
5861    * (the default) or width for height.
5862    *
5863    * For actors implementing height for width, the parent container should get
5864    * the preferred width first, and then the preferred height for that width.
5865    *
5866    * For actors implementing width for height, the parent container should get
5867    * the preferred height first, and then the preferred width for that height.
5868    *
5869    * For instance:
5870    *
5871    * |[
5872    *   ClutterRequestMode mode;
5873    *   gfloat natural_width, min_width;
5874    *   gfloat natural_height, min_height;
5875    *
5876    *   mode = clutter_actor_get_request_mode (child);
5877    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5878    *     {
5879    *       clutter_actor_get_preferred_width (child, -1,
5880    *                                          &amp;min_width,
5881    *                                          &amp;natural_width);
5882    *       clutter_actor_get_preferred_height (child, natural_width,
5883    *                                           &amp;min_height,
5884    *                                           &amp;natural_height);
5885    *     }
5886    *   else
5887    *     {
5888    *       clutter_actor_get_preferred_height (child, -1,
5889    *                                           &amp;min_height,
5890    *                                           &amp;natural_height);
5891    *       clutter_actor_get_preferred_width (child, natural_height,
5892    *                                          &amp;min_width,
5893    *                                          &amp;natural_width);
5894    *     }
5895    * ]|
5896    *
5897    * will retrieve the minimum and natural width and height depending on the
5898    * preferred request mode of the #ClutterActor "child".
5899    *
5900    * The clutter_actor_get_preferred_size() function will implement this
5901    * check for you.
5902    *
5903    * Since: 0.8
5904    */
5905   obj_props[PROP_REQUEST_MODE] =
5906     g_param_spec_enum ("request-mode",
5907                        P_("Request Mode"),
5908                        P_("The actor's request mode"),
5909                        CLUTTER_TYPE_REQUEST_MODE,
5910                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5911                        CLUTTER_PARAM_READWRITE);
5912
5913   /**
5914    * ClutterActor:depth:
5915    *
5916    * The position of the actor on the Z axis.
5917    *
5918    * The #ClutterActor:depth property is relative to the parent's
5919    * modelview matrix.
5920    *
5921    * The #ClutterActor:depth property is animatable.
5922    *
5923    * Since: 0.6
5924    */
5925   obj_props[PROP_DEPTH] =
5926     g_param_spec_float ("depth",
5927                         P_("Depth"),
5928                         P_("Position on the Z axis"),
5929                         -G_MAXFLOAT, G_MAXFLOAT,
5930                         0.0,
5931                         G_PARAM_READWRITE |
5932                         G_PARAM_STATIC_STRINGS |
5933                         CLUTTER_PARAM_ANIMATABLE);
5934
5935   /**
5936    * ClutterActor:opacity:
5937    *
5938    * Opacity of an actor, between 0 (fully transparent) and
5939    * 255 (fully opaque)
5940    *
5941    * The #ClutterActor:opacity property is animatable.
5942    */
5943   obj_props[PROP_OPACITY] =
5944     g_param_spec_uint ("opacity",
5945                        P_("Opacity"),
5946                        P_("Opacity of an actor"),
5947                        0, 255,
5948                        255,
5949                        G_PARAM_READWRITE |
5950                        G_PARAM_STATIC_STRINGS |
5951                        CLUTTER_PARAM_ANIMATABLE);
5952
5953   /**
5954    * ClutterActor:offscreen-redirect:
5955    *
5956    * Determines the conditions in which the actor will be redirected
5957    * to an offscreen framebuffer while being painted. For example this
5958    * can be used to cache an actor in a framebuffer or for improved
5959    * handling of transparent actors. See
5960    * clutter_actor_set_offscreen_redirect() for details.
5961    *
5962    * Since: 1.8
5963    */
5964   obj_props[PROP_OFFSCREEN_REDIRECT] =
5965     g_param_spec_flags ("offscreen-redirect",
5966                         P_("Offscreen redirect"),
5967                         P_("Flags controlling when to flatten the actor into a single image"),
5968                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5969                         0,
5970                         CLUTTER_PARAM_READWRITE);
5971
5972   /**
5973    * ClutterActor:visible:
5974    *
5975    * Whether the actor is set to be visible or not
5976    *
5977    * See also #ClutterActor:mapped
5978    */
5979   obj_props[PROP_VISIBLE] =
5980     g_param_spec_boolean ("visible",
5981                           P_("Visible"),
5982                           P_("Whether the actor is visible or not"),
5983                           FALSE,
5984                           CLUTTER_PARAM_READWRITE);
5985
5986   /**
5987    * ClutterActor:mapped:
5988    *
5989    * Whether the actor is mapped (will be painted when the stage
5990    * to which it belongs is mapped)
5991    *
5992    * Since: 1.0
5993    */
5994   obj_props[PROP_MAPPED] =
5995     g_param_spec_boolean ("mapped",
5996                           P_("Mapped"),
5997                           P_("Whether the actor will be painted"),
5998                           FALSE,
5999                           CLUTTER_PARAM_READABLE);
6000
6001   /**
6002    * ClutterActor:realized:
6003    *
6004    * Whether the actor has been realized
6005    *
6006    * Since: 1.0
6007    */
6008   obj_props[PROP_REALIZED] =
6009     g_param_spec_boolean ("realized",
6010                           P_("Realized"),
6011                           P_("Whether the actor has been realized"),
6012                           FALSE,
6013                           CLUTTER_PARAM_READABLE);
6014
6015   /**
6016    * ClutterActor:reactive:
6017    *
6018    * Whether the actor is reactive to events or not
6019    *
6020    * Only reactive actors will emit event-related signals
6021    *
6022    * Since: 0.6
6023    */
6024   obj_props[PROP_REACTIVE] =
6025     g_param_spec_boolean ("reactive",
6026                           P_("Reactive"),
6027                           P_("Whether the actor is reactive to events"),
6028                           FALSE,
6029                           CLUTTER_PARAM_READWRITE);
6030
6031   /**
6032    * ClutterActor:has-clip:
6033    *
6034    * Whether the actor has the #ClutterActor:clip property set or not
6035    */
6036   obj_props[PROP_HAS_CLIP] =
6037     g_param_spec_boolean ("has-clip",
6038                           P_("Has Clip"),
6039                           P_("Whether the actor has a clip set"),
6040                           FALSE,
6041                           CLUTTER_PARAM_READABLE);
6042
6043   /**
6044    * ClutterActor:clip:
6045    *
6046    * The clip region for the actor, in actor-relative coordinates
6047    *
6048    * Every part of the actor outside the clip region will not be
6049    * painted
6050    */
6051   obj_props[PROP_CLIP] =
6052     g_param_spec_boxed ("clip",
6053                         P_("Clip"),
6054                         P_("The clip region for the actor"),
6055                         CLUTTER_TYPE_GEOMETRY,
6056                         CLUTTER_PARAM_READWRITE);
6057
6058   /**
6059    * ClutterActor:name:
6060    *
6061    * The name of the actor
6062    *
6063    * Since: 0.2
6064    */
6065   obj_props[PROP_NAME] =
6066     g_param_spec_string ("name",
6067                          P_("Name"),
6068                          P_("Name of the actor"),
6069                          NULL,
6070                          CLUTTER_PARAM_READWRITE);
6071
6072   /**
6073    * ClutterActor:scale-x:
6074    *
6075    * The horizontal scale of the actor.
6076    *
6077    * The #ClutterActor:scale-x property is animatable.
6078    *
6079    * Since: 0.6
6080    */
6081   obj_props[PROP_SCALE_X] =
6082     g_param_spec_double ("scale-x",
6083                          P_("Scale X"),
6084                          P_("Scale factor on the X axis"),
6085                          0.0, G_MAXDOUBLE,
6086                          1.0,
6087                          G_PARAM_READWRITE |
6088                          G_PARAM_STATIC_STRINGS |
6089                          CLUTTER_PARAM_ANIMATABLE);
6090
6091   /**
6092    * ClutterActor:scale-y:
6093    *
6094    * The vertical scale of the actor.
6095    *
6096    * The #ClutterActor:scale-y property is animatable.
6097    *
6098    * Since: 0.6
6099    */
6100   obj_props[PROP_SCALE_Y] =
6101     g_param_spec_double ("scale-y",
6102                          P_("Scale Y"),
6103                          P_("Scale factor on the Y axis"),
6104                          0.0, G_MAXDOUBLE,
6105                          1.0,
6106                          G_PARAM_READWRITE |
6107                          G_PARAM_STATIC_STRINGS |
6108                          CLUTTER_PARAM_ANIMATABLE);
6109
6110   /**
6111    * ClutterActor:scale-center-x:
6112    *
6113    * The horizontal center point for scaling
6114    *
6115    * Since: 1.0
6116    */
6117   obj_props[PROP_SCALE_CENTER_X] =
6118     g_param_spec_float ("scale-center-x",
6119                         P_("Scale Center X"),
6120                         P_("Horizontal scale center"),
6121                         -G_MAXFLOAT, G_MAXFLOAT,
6122                         0.0,
6123                         CLUTTER_PARAM_READWRITE);
6124
6125   /**
6126    * ClutterActor:scale-center-y:
6127    *
6128    * The vertical center point for scaling
6129    *
6130    * Since: 1.0
6131    */
6132   obj_props[PROP_SCALE_CENTER_Y] =
6133     g_param_spec_float ("scale-center-y",
6134                         P_("Scale Center Y"),
6135                         P_("Vertical scale center"),
6136                         -G_MAXFLOAT, G_MAXFLOAT,
6137                         0.0,
6138                         CLUTTER_PARAM_READWRITE);
6139
6140   /**
6141    * ClutterActor:scale-gravity:
6142    *
6143    * The center point for scaling expressed as a #ClutterGravity
6144    *
6145    * Since: 1.0
6146    */
6147   obj_props[PROP_SCALE_GRAVITY] =
6148     g_param_spec_enum ("scale-gravity",
6149                        P_("Scale Gravity"),
6150                        P_("The center of scaling"),
6151                        CLUTTER_TYPE_GRAVITY,
6152                        CLUTTER_GRAVITY_NONE,
6153                        CLUTTER_PARAM_READWRITE);
6154
6155   /**
6156    * ClutterActor:rotation-angle-x:
6157    *
6158    * The rotation angle on the X axis.
6159    *
6160    * The #ClutterActor:rotation-angle-x property is animatable.
6161    *
6162    * Since: 0.6
6163    */
6164   obj_props[PROP_ROTATION_ANGLE_X] =
6165     g_param_spec_double ("rotation-angle-x",
6166                          P_("Rotation Angle X"),
6167                          P_("The rotation angle on the X axis"),
6168                          -G_MAXDOUBLE, G_MAXDOUBLE,
6169                          0.0,
6170                          G_PARAM_READWRITE |
6171                          G_PARAM_STATIC_STRINGS |
6172                          CLUTTER_PARAM_ANIMATABLE);
6173
6174   /**
6175    * ClutterActor:rotation-angle-y:
6176    *
6177    * The rotation angle on the Y axis
6178    *
6179    * The #ClutterActor:rotation-angle-y property is animatable.
6180    *
6181    * Since: 0.6
6182    */
6183   obj_props[PROP_ROTATION_ANGLE_Y] =
6184     g_param_spec_double ("rotation-angle-y",
6185                          P_("Rotation Angle Y"),
6186                          P_("The rotation angle on the Y axis"),
6187                          -G_MAXDOUBLE, G_MAXDOUBLE,
6188                          0.0,
6189                          G_PARAM_READWRITE |
6190                          G_PARAM_STATIC_STRINGS |
6191                          CLUTTER_PARAM_ANIMATABLE);
6192
6193   /**
6194    * ClutterActor:rotation-angle-z:
6195    *
6196    * The rotation angle on the Z axis
6197    *
6198    * The #ClutterActor:rotation-angle-z property is animatable.
6199    *
6200    * Since: 0.6
6201    */
6202   obj_props[PROP_ROTATION_ANGLE_Z] =
6203     g_param_spec_double ("rotation-angle-z",
6204                          P_("Rotation Angle Z"),
6205                          P_("The rotation angle on the Z axis"),
6206                          -G_MAXDOUBLE, G_MAXDOUBLE,
6207                          0.0,
6208                          G_PARAM_READWRITE |
6209                          G_PARAM_STATIC_STRINGS |
6210                          CLUTTER_PARAM_ANIMATABLE);
6211
6212   /**
6213    * ClutterActor:rotation-center-x:
6214    *
6215    * The rotation center on the X axis.
6216    *
6217    * Since: 0.6
6218    */
6219   obj_props[PROP_ROTATION_CENTER_X] =
6220     g_param_spec_boxed ("rotation-center-x",
6221                         P_("Rotation Center X"),
6222                         P_("The rotation center on the X axis"),
6223                         CLUTTER_TYPE_VERTEX,
6224                         CLUTTER_PARAM_READWRITE);
6225
6226   /**
6227    * ClutterActor:rotation-center-y:
6228    *
6229    * The rotation center on the Y axis.
6230    *
6231    * Since: 0.6
6232    */
6233   obj_props[PROP_ROTATION_CENTER_Y] =
6234     g_param_spec_boxed ("rotation-center-y",
6235                         P_("Rotation Center Y"),
6236                         P_("The rotation center on the Y axis"),
6237                         CLUTTER_TYPE_VERTEX,
6238                         CLUTTER_PARAM_READWRITE);
6239
6240   /**
6241    * ClutterActor:rotation-center-z:
6242    *
6243    * The rotation center on the Z axis.
6244    *
6245    * Since: 0.6
6246    */
6247   obj_props[PROP_ROTATION_CENTER_Z] =
6248     g_param_spec_boxed ("rotation-center-z",
6249                         P_("Rotation Center Z"),
6250                         P_("The rotation center on the Z axis"),
6251                         CLUTTER_TYPE_VERTEX,
6252                         CLUTTER_PARAM_READWRITE);
6253
6254   /**
6255    * ClutterActor:rotation-center-z-gravity:
6256    *
6257    * The rotation center on the Z axis expressed as a #ClutterGravity.
6258    *
6259    * Since: 1.0
6260    */
6261   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6262     g_param_spec_enum ("rotation-center-z-gravity",
6263                        P_("Rotation Center Z Gravity"),
6264                        P_("Center point for rotation around the Z axis"),
6265                        CLUTTER_TYPE_GRAVITY,
6266                        CLUTTER_GRAVITY_NONE,
6267                        CLUTTER_PARAM_READWRITE);
6268
6269   /**
6270    * ClutterActor:anchor-x:
6271    *
6272    * The X coordinate of an actor's anchor point, relative to
6273    * the actor coordinate space, in pixels
6274    *
6275    * Since: 0.8
6276    */
6277   obj_props[PROP_ANCHOR_X] =
6278     g_param_spec_float ("anchor-x",
6279                         P_("Anchor X"),
6280                         P_("X coordinate of the anchor point"),
6281                         -G_MAXFLOAT, G_MAXFLOAT,
6282                         0,
6283                         CLUTTER_PARAM_READWRITE);
6284
6285   /**
6286    * ClutterActor:anchor-y:
6287    *
6288    * The Y coordinate of an actor's anchor point, relative to
6289    * the actor coordinate space, in pixels
6290    *
6291    * Since: 0.8
6292    */
6293   obj_props[PROP_ANCHOR_Y] =
6294     g_param_spec_float ("anchor-y",
6295                         P_("Anchor Y"),
6296                         P_("Y coordinate of the anchor point"),
6297                         -G_MAXFLOAT, G_MAXFLOAT,
6298                         0,
6299                         CLUTTER_PARAM_READWRITE);
6300
6301   /**
6302    * ClutterActor:anchor-gravity:
6303    *
6304    * The anchor point expressed as a #ClutterGravity
6305    *
6306    * Since: 1.0
6307    */
6308   obj_props[PROP_ANCHOR_GRAVITY] =
6309     g_param_spec_enum ("anchor-gravity",
6310                        P_("Anchor Gravity"),
6311                        P_("The anchor point as a ClutterGravity"),
6312                        CLUTTER_TYPE_GRAVITY,
6313                        CLUTTER_GRAVITY_NONE,
6314                        CLUTTER_PARAM_READWRITE);
6315
6316   /**
6317    * ClutterActor:show-on-set-parent:
6318    *
6319    * If %TRUE, the actor is automatically shown when parented.
6320    *
6321    * Calling clutter_actor_hide() on an actor which has not been
6322    * parented will set this property to %FALSE as a side effect.
6323    *
6324    * Since: 0.8
6325    */
6326   obj_props[PROP_SHOW_ON_SET_PARENT] =
6327     g_param_spec_boolean ("show-on-set-parent",
6328                           P_("Show on set parent"),
6329                           P_("Whether the actor is shown when parented"),
6330                           TRUE,
6331                           CLUTTER_PARAM_READWRITE);
6332
6333   /**
6334    * ClutterActor:clip-to-allocation:
6335    *
6336    * Whether the clip region should track the allocated area
6337    * of the actor.
6338    *
6339    * This property is ignored if a clip area has been explicitly
6340    * set using clutter_actor_set_clip().
6341    *
6342    * Since: 1.0
6343    */
6344   obj_props[PROP_CLIP_TO_ALLOCATION] =
6345     g_param_spec_boolean ("clip-to-allocation",
6346                           P_("Clip to Allocation"),
6347                           P_("Sets the clip region to track the actor's allocation"),
6348                           FALSE,
6349                           CLUTTER_PARAM_READWRITE);
6350
6351   /**
6352    * ClutterActor:text-direction:
6353    *
6354    * The direction of the text inside a #ClutterActor.
6355    *
6356    * Since: 1.0
6357    */
6358   obj_props[PROP_TEXT_DIRECTION] =
6359     g_param_spec_enum ("text-direction",
6360                        P_("Text Direction"),
6361                        P_("Direction of the text"),
6362                        CLUTTER_TYPE_TEXT_DIRECTION,
6363                        CLUTTER_TEXT_DIRECTION_LTR,
6364                        CLUTTER_PARAM_READWRITE);
6365
6366   /**
6367    * ClutterActor:has-pointer:
6368    *
6369    * Whether the actor contains the pointer of a #ClutterInputDevice
6370    * or not.
6371    *
6372    * Since: 1.2
6373    */
6374   obj_props[PROP_HAS_POINTER] =
6375     g_param_spec_boolean ("has-pointer",
6376                           P_("Has Pointer"),
6377                           P_("Whether the actor contains the pointer of an input device"),
6378                           FALSE,
6379                           CLUTTER_PARAM_READABLE);
6380
6381   /**
6382    * ClutterActor:actions:
6383    *
6384    * Adds a #ClutterAction to the actor
6385    *
6386    * Since: 1.4
6387    */
6388   obj_props[PROP_ACTIONS] =
6389     g_param_spec_object ("actions",
6390                          P_("Actions"),
6391                          P_("Adds an action to the actor"),
6392                          CLUTTER_TYPE_ACTION,
6393                          CLUTTER_PARAM_WRITABLE);
6394
6395   /**
6396    * ClutterActor:constraints:
6397    *
6398    * Adds a #ClutterConstraint to the actor
6399    *
6400    * Since: 1.4
6401    */
6402   obj_props[PROP_CONSTRAINTS] =
6403     g_param_spec_object ("constraints",
6404                          P_("Constraints"),
6405                          P_("Adds a constraint to the actor"),
6406                          CLUTTER_TYPE_CONSTRAINT,
6407                          CLUTTER_PARAM_WRITABLE);
6408
6409   /**
6410    * ClutterActor:effect:
6411    *
6412    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6413    *
6414    * Since: 1.4
6415    */
6416   obj_props[PROP_EFFECT] =
6417     g_param_spec_object ("effect",
6418                          P_("Effect"),
6419                          P_("Add an effect to be applied on the actor"),
6420                          CLUTTER_TYPE_EFFECT,
6421                          CLUTTER_PARAM_WRITABLE);
6422
6423   /**
6424    * ClutterActor:layout-manager:
6425    *
6426    * A delegate object for controlling the layout of the children of
6427    * an actor.
6428    *
6429    * Since: 1.10
6430    */
6431   obj_props[PROP_LAYOUT_MANAGER] =
6432     g_param_spec_object ("layout-manager",
6433                          P_("Layout Manager"),
6434                          P_("The object controlling the layout of an actor's children"),
6435                          CLUTTER_TYPE_LAYOUT_MANAGER,
6436                          CLUTTER_PARAM_READWRITE);
6437
6438   /**
6439    * ClutterActor:x-expand:
6440    *
6441    * Whether a layout manager should assign more space to the actor on
6442    * the X axis.
6443    *
6444    * Since: 1.12
6445    */
6446   obj_props[PROP_X_EXPAND] =
6447     g_param_spec_boolean ("x-expand",
6448                           P_("X Expand"),
6449                           P_("Whether extra horizontal space should be assigned to the actor"),
6450                           FALSE,
6451                           G_PARAM_READWRITE |
6452                           G_PARAM_STATIC_STRINGS);
6453
6454   /**
6455    * ClutterActor:y-expand:
6456    *
6457    * Whether a layout manager should assign more space to the actor on
6458    * the Y axis.
6459    *
6460    * Since: 1.12
6461    */
6462   obj_props[PROP_Y_EXPAND] =
6463     g_param_spec_boolean ("y-expand",
6464                           P_("Y Expand"),
6465                           P_("Whether extra vertical space should be assigned to the actor"),
6466                           FALSE,
6467                           G_PARAM_READWRITE |
6468                           G_PARAM_STATIC_STRINGS);
6469
6470   /**
6471    * ClutterActor:x-align:
6472    *
6473    * The alignment of an actor on the X axis, if the actor has been given
6474    * extra space for its allocation. See also the #ClutterActor:x-expand
6475    * property.
6476    *
6477    * Since: 1.10
6478    */
6479   obj_props[PROP_X_ALIGN] =
6480     g_param_spec_enum ("x-align",
6481                        P_("X Alignment"),
6482                        P_("The alignment of the actor on the X axis within its allocation"),
6483                        CLUTTER_TYPE_ACTOR_ALIGN,
6484                        CLUTTER_ACTOR_ALIGN_FILL,
6485                        CLUTTER_PARAM_READWRITE);
6486
6487   /**
6488    * ClutterActor:y-align:
6489    *
6490    * The alignment of an actor on the Y axis, if the actor has been given
6491    * extra space for its allocation.
6492    *
6493    * Since: 1.10
6494    */
6495   obj_props[PROP_Y_ALIGN] =
6496     g_param_spec_enum ("y-align",
6497                        P_("Y Alignment"),
6498                        P_("The alignment of the actor on the Y axis within its allocation"),
6499                        CLUTTER_TYPE_ACTOR_ALIGN,
6500                        CLUTTER_ACTOR_ALIGN_FILL,
6501                        CLUTTER_PARAM_READWRITE);
6502
6503   /**
6504    * ClutterActor:margin-top:
6505    *
6506    * The margin (in pixels) from the top of the actor.
6507    *
6508    * This property adds a margin to the actor's preferred size; the margin
6509    * will be automatically taken into account when allocating the actor.
6510    *
6511    * Since: 1.10
6512    */
6513   obj_props[PROP_MARGIN_TOP] =
6514     g_param_spec_float ("margin-top",
6515                         P_("Margin Top"),
6516                         P_("Extra space at the top"),
6517                         0.0, G_MAXFLOAT,
6518                         0.0,
6519                         CLUTTER_PARAM_READWRITE);
6520
6521   /**
6522    * ClutterActor:margin-bottom:
6523    *
6524    * The margin (in pixels) from the bottom of the actor.
6525    *
6526    * This property adds a margin to the actor's preferred size; the margin
6527    * will be automatically taken into account when allocating the actor.
6528    *
6529    * Since: 1.10
6530    */
6531   obj_props[PROP_MARGIN_BOTTOM] =
6532     g_param_spec_float ("margin-bottom",
6533                         P_("Margin Bottom"),
6534                         P_("Extra space at the bottom"),
6535                         0.0, G_MAXFLOAT,
6536                         0.0,
6537                         CLUTTER_PARAM_READWRITE);
6538
6539   /**
6540    * ClutterActor:margin-left:
6541    *
6542    * The margin (in pixels) from the left of the actor.
6543    *
6544    * This property adds a margin to the actor's preferred size; the margin
6545    * will be automatically taken into account when allocating the actor.
6546    *
6547    * Since: 1.10
6548    */
6549   obj_props[PROP_MARGIN_LEFT] =
6550     g_param_spec_float ("margin-left",
6551                         P_("Margin Left"),
6552                         P_("Extra space at the left"),
6553                         0.0, G_MAXFLOAT,
6554                         0.0,
6555                         CLUTTER_PARAM_READWRITE);
6556
6557   /**
6558    * ClutterActor:margin-right:
6559    *
6560    * The margin (in pixels) from the right of the actor.
6561    *
6562    * This property adds a margin to the actor's preferred size; the margin
6563    * will be automatically taken into account when allocating the actor.
6564    *
6565    * Since: 1.10
6566    */
6567   obj_props[PROP_MARGIN_RIGHT] =
6568     g_param_spec_float ("margin-right",
6569                         P_("Margin Right"),
6570                         P_("Extra space at the right"),
6571                         0.0, G_MAXFLOAT,
6572                         0.0,
6573                         CLUTTER_PARAM_READWRITE);
6574
6575   /**
6576    * ClutterActor:background-color-set:
6577    *
6578    * Whether the #ClutterActor:background-color property has been set.
6579    *
6580    * Since: 1.10
6581    */
6582   obj_props[PROP_BACKGROUND_COLOR_SET] =
6583     g_param_spec_boolean ("background-color-set",
6584                           P_("Background Color Set"),
6585                           P_("Whether the background color is set"),
6586                           FALSE,
6587                           CLUTTER_PARAM_READABLE);
6588
6589   /**
6590    * ClutterActor:background-color:
6591    *
6592    * Paints a solid fill of the actor's allocation using the specified
6593    * color.
6594    *
6595    * The #ClutterActor:background-color property is animatable.
6596    *
6597    * Since: 1.10
6598    */
6599   obj_props[PROP_BACKGROUND_COLOR] =
6600     clutter_param_spec_color ("background-color",
6601                               P_("Background color"),
6602                               P_("The actor's background color"),
6603                               CLUTTER_COLOR_Transparent,
6604                               G_PARAM_READWRITE |
6605                               G_PARAM_STATIC_STRINGS |
6606                               CLUTTER_PARAM_ANIMATABLE);
6607
6608   /**
6609    * ClutterActor:first-child:
6610    *
6611    * The actor's first child.
6612    *
6613    * Since: 1.10
6614    */
6615   obj_props[PROP_FIRST_CHILD] =
6616     g_param_spec_object ("first-child",
6617                          P_("First Child"),
6618                          P_("The actor's first child"),
6619                          CLUTTER_TYPE_ACTOR,
6620                          CLUTTER_PARAM_READABLE);
6621
6622   /**
6623    * ClutterActor:last-child:
6624    *
6625    * The actor's last child.
6626    *
6627    * Since: 1.10
6628    */
6629   obj_props[PROP_LAST_CHILD] =
6630     g_param_spec_object ("last-child",
6631                          P_("Last Child"),
6632                          P_("The actor's last child"),
6633                          CLUTTER_TYPE_ACTOR,
6634                          CLUTTER_PARAM_READABLE);
6635
6636   /**
6637    * ClutterActor:content:
6638    *
6639    * The #ClutterContent implementation that controls the content
6640    * of the actor.
6641    *
6642    * Since: 1.10
6643    */
6644   obj_props[PROP_CONTENT] =
6645     g_param_spec_object ("content",
6646                          P_("Content"),
6647                          P_("Delegate object for painting the actor's content"),
6648                          CLUTTER_TYPE_CONTENT,
6649                          CLUTTER_PARAM_READWRITE);
6650
6651   /**
6652    * ClutterActor:content-gravity:
6653    *
6654    * The alignment that should be honoured by the #ClutterContent
6655    * set with the #ClutterActor:content property.
6656    *
6657    * Changing the value of this property will change the bounding box of
6658    * the content; you can use the #ClutterActor:content-box property to
6659    * get the position and size of the content within the actor's
6660    * allocation.
6661    *
6662    * This property is meaningful only for #ClutterContent implementations
6663    * that have a preferred size, and if the preferred size is smaller than
6664    * the actor's allocation.
6665    *
6666    * The #ClutterActor:content-gravity property is animatable.
6667    *
6668    * Since: 1.10
6669    */
6670   obj_props[PROP_CONTENT_GRAVITY] =
6671     g_param_spec_enum ("content-gravity",
6672                        P_("Content Gravity"),
6673                        P_("Alignment of the actor's content"),
6674                        CLUTTER_TYPE_CONTENT_GRAVITY,
6675                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6676                        CLUTTER_PARAM_READWRITE);
6677
6678   /**
6679    * ClutterActor:content-box:
6680    *
6681    * The bounding box for the #ClutterContent used by the actor.
6682    *
6683    * The value of this property is controlled by the #ClutterActor:allocation
6684    * and #ClutterActor:content-gravity properties of #ClutterActor.
6685    *
6686    * The bounding box for the content is guaranteed to never exceed the
6687    * allocation's of the actor.
6688    *
6689    * Since: 1.10
6690    */
6691   obj_props[PROP_CONTENT_BOX] =
6692     g_param_spec_boxed ("content-box",
6693                         P_("Content Box"),
6694                         P_("The bounding box of the actor's content"),
6695                         CLUTTER_TYPE_ACTOR_BOX,
6696                         G_PARAM_READABLE |
6697                         G_PARAM_STATIC_STRINGS |
6698                         CLUTTER_PARAM_ANIMATABLE);
6699
6700   obj_props[PROP_MINIFICATION_FILTER] =
6701     g_param_spec_enum ("minification-filter",
6702                        P_("Minification Filter"),
6703                        P_("The filter used when reducing the size of the content"),
6704                        CLUTTER_TYPE_SCALING_FILTER,
6705                        CLUTTER_SCALING_FILTER_LINEAR,
6706                        CLUTTER_PARAM_READWRITE);
6707
6708   obj_props[PROP_MAGNIFICATION_FILTER] =
6709     g_param_spec_enum ("magnification-filter",
6710                        P_("Magnification Filter"),
6711                        P_("The filter used when increasing the size of the content"),
6712                        CLUTTER_TYPE_SCALING_FILTER,
6713                        CLUTTER_SCALING_FILTER_LINEAR,
6714                        CLUTTER_PARAM_READWRITE);
6715
6716   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6717
6718   /**
6719    * ClutterActor::destroy:
6720    * @actor: the #ClutterActor which emitted the signal
6721    *
6722    * The ::destroy signal notifies that all references held on the
6723    * actor which emitted it should be released.
6724    *
6725    * The ::destroy signal should be used by all holders of a reference
6726    * on @actor.
6727    *
6728    * This signal might result in the finalization of the #ClutterActor
6729    * if all references are released.
6730    *
6731    * Composite actors and actors implementing the #ClutterContainer
6732    * interface should override the default implementation of the
6733    * class handler of this signal and call clutter_actor_destroy() on
6734    * their children. When overriding the default class handler, it is
6735    * required to chain up to the parent's implementation.
6736    *
6737    * Since: 0.2
6738    */
6739   actor_signals[DESTROY] =
6740     g_signal_new (I_("destroy"),
6741                   G_TYPE_FROM_CLASS (object_class),
6742                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6743                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6744                   NULL, NULL,
6745                   _clutter_marshal_VOID__VOID,
6746                   G_TYPE_NONE, 0);
6747   /**
6748    * ClutterActor::show:
6749    * @actor: the object which received the signal
6750    *
6751    * The ::show signal is emitted when an actor is visible and
6752    * rendered on the stage.
6753    *
6754    * Since: 0.2
6755    */
6756   actor_signals[SHOW] =
6757     g_signal_new (I_("show"),
6758                   G_TYPE_FROM_CLASS (object_class),
6759                   G_SIGNAL_RUN_FIRST,
6760                   G_STRUCT_OFFSET (ClutterActorClass, show),
6761                   NULL, NULL,
6762                   _clutter_marshal_VOID__VOID,
6763                   G_TYPE_NONE, 0);
6764   /**
6765    * ClutterActor::hide:
6766    * @actor: the object which received the signal
6767    *
6768    * The ::hide signal is emitted when an actor is no longer rendered
6769    * on the stage.
6770    *
6771    * Since: 0.2
6772    */
6773   actor_signals[HIDE] =
6774     g_signal_new (I_("hide"),
6775                   G_TYPE_FROM_CLASS (object_class),
6776                   G_SIGNAL_RUN_FIRST,
6777                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6778                   NULL, NULL,
6779                   _clutter_marshal_VOID__VOID,
6780                   G_TYPE_NONE, 0);
6781   /**
6782    * ClutterActor::parent-set:
6783    * @actor: the object which received the signal
6784    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6785    *
6786    * This signal is emitted when the parent of the actor changes.
6787    *
6788    * Since: 0.2
6789    */
6790   actor_signals[PARENT_SET] =
6791     g_signal_new (I_("parent-set"),
6792                   G_TYPE_FROM_CLASS (object_class),
6793                   G_SIGNAL_RUN_LAST,
6794                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6795                   NULL, NULL,
6796                   _clutter_marshal_VOID__OBJECT,
6797                   G_TYPE_NONE, 1,
6798                   CLUTTER_TYPE_ACTOR);
6799
6800   /**
6801    * ClutterActor::queue-redraw:
6802    * @actor: the actor we're bubbling the redraw request through
6803    * @origin: the actor which initiated the redraw request
6804    *
6805    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6806    * is called on @origin.
6807    *
6808    * The default implementation for #ClutterActor chains up to the
6809    * parent actor and queues a redraw on the parent, thus "bubbling"
6810    * the redraw queue up through the actor graph. The default
6811    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6812    * in a main loop idle handler.
6813    *
6814    * Note that the @origin actor may be the stage, or a container; it
6815    * does not have to be a leaf node in the actor graph.
6816    *
6817    * Toolkits embedding a #ClutterStage which require a redraw and
6818    * relayout cycle can stop the emission of this signal using the
6819    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6820    * themselves, like:
6821    *
6822    * |[
6823    *   static void
6824    *   on_redraw_complete (gpointer data)
6825    *   {
6826    *     ClutterStage *stage = data;
6827    *
6828    *     /&ast; execute the Clutter drawing pipeline &ast;/
6829    *     clutter_stage_ensure_redraw (stage);
6830    *   }
6831    *
6832    *   static void
6833    *   on_stage_queue_redraw (ClutterStage *stage)
6834    *   {
6835    *     /&ast; this prevents the default handler to run &ast;/
6836    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6837    *
6838    *     /&ast; queue a redraw with the host toolkit and call
6839    *      &ast; a function when the redraw has been completed
6840    *      &ast;/
6841    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6842    *   }
6843    * ]|
6844    *
6845    * <note><para>This signal is emitted before the Clutter paint
6846    * pipeline is executed. If you want to know when the pipeline has
6847    * been completed you should connect to the ::paint signal on the
6848    * Stage with g_signal_connect_after().</para></note>
6849    *
6850    * Since: 1.0
6851    */
6852   actor_signals[QUEUE_REDRAW] =
6853     g_signal_new (I_("queue-redraw"),
6854                   G_TYPE_FROM_CLASS (object_class),
6855                   G_SIGNAL_RUN_LAST |
6856                   G_SIGNAL_NO_HOOKS,
6857                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6858                   NULL, NULL,
6859                   _clutter_marshal_VOID__OBJECT,
6860                   G_TYPE_NONE, 1,
6861                   CLUTTER_TYPE_ACTOR);
6862
6863   /**
6864    * ClutterActor::queue-relayout
6865    * @actor: the actor being queued for relayout
6866    *
6867    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6868    * is called on an actor.
6869    *
6870    * The default implementation for #ClutterActor chains up to the
6871    * parent actor and queues a relayout on the parent, thus "bubbling"
6872    * the relayout queue up through the actor graph.
6873    *
6874    * The main purpose of this signal is to allow relayout to be propagated
6875    * properly in the procense of #ClutterClone actors. Applications will
6876    * not normally need to connect to this signal.
6877    *
6878    * Since: 1.2
6879    */
6880   actor_signals[QUEUE_RELAYOUT] =
6881     g_signal_new (I_("queue-relayout"),
6882                   G_TYPE_FROM_CLASS (object_class),
6883                   G_SIGNAL_RUN_LAST |
6884                   G_SIGNAL_NO_HOOKS,
6885                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6886                   NULL, NULL,
6887                   _clutter_marshal_VOID__VOID,
6888                   G_TYPE_NONE, 0);
6889
6890   /**
6891    * ClutterActor::event:
6892    * @actor: the actor which received the event
6893    * @event: a #ClutterEvent
6894    *
6895    * The ::event signal is emitted each time an event is received
6896    * by the @actor. This signal will be emitted on every actor,
6897    * following the hierarchy chain, until it reaches the top-level
6898    * container (the #ClutterStage).
6899    *
6900    * Return value: %TRUE if the event has been handled by the actor,
6901    *   or %FALSE to continue the emission.
6902    *
6903    * Since: 0.6
6904    */
6905   actor_signals[EVENT] =
6906     g_signal_new (I_("event"),
6907                   G_TYPE_FROM_CLASS (object_class),
6908                   G_SIGNAL_RUN_LAST,
6909                   G_STRUCT_OFFSET (ClutterActorClass, event),
6910                   _clutter_boolean_handled_accumulator, NULL,
6911                   _clutter_marshal_BOOLEAN__BOXED,
6912                   G_TYPE_BOOLEAN, 1,
6913                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6914   /**
6915    * ClutterActor::button-press-event:
6916    * @actor: the actor which received the event
6917    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6918    *
6919    * The ::button-press-event signal is emitted each time a mouse button
6920    * is pressed on @actor.
6921    *
6922    * Return value: %TRUE if the event has been handled by the actor,
6923    *   or %FALSE to continue the emission.
6924    *
6925    * Since: 0.6
6926    */
6927   actor_signals[BUTTON_PRESS_EVENT] =
6928     g_signal_new (I_("button-press-event"),
6929                   G_TYPE_FROM_CLASS (object_class),
6930                   G_SIGNAL_RUN_LAST,
6931                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6932                   _clutter_boolean_handled_accumulator, NULL,
6933                   _clutter_marshal_BOOLEAN__BOXED,
6934                   G_TYPE_BOOLEAN, 1,
6935                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6936   /**
6937    * ClutterActor::button-release-event:
6938    * @actor: the actor which received the event
6939    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6940    *
6941    * The ::button-release-event signal is emitted each time a mouse button
6942    * is released on @actor.
6943    *
6944    * Return value: %TRUE if the event has been handled by the actor,
6945    *   or %FALSE to continue the emission.
6946    *
6947    * Since: 0.6
6948    */
6949   actor_signals[BUTTON_RELEASE_EVENT] =
6950     g_signal_new (I_("button-release-event"),
6951                   G_TYPE_FROM_CLASS (object_class),
6952                   G_SIGNAL_RUN_LAST,
6953                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6954                   _clutter_boolean_handled_accumulator, NULL,
6955                   _clutter_marshal_BOOLEAN__BOXED,
6956                   G_TYPE_BOOLEAN, 1,
6957                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6958   /**
6959    * ClutterActor::scroll-event:
6960    * @actor: the actor which received the event
6961    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6962    *
6963    * The ::scroll-event signal is emitted each time the mouse is
6964    * scrolled on @actor
6965    *
6966    * Return value: %TRUE if the event has been handled by the actor,
6967    *   or %FALSE to continue the emission.
6968    *
6969    * Since: 0.6
6970    */
6971   actor_signals[SCROLL_EVENT] =
6972     g_signal_new (I_("scroll-event"),
6973                   G_TYPE_FROM_CLASS (object_class),
6974                   G_SIGNAL_RUN_LAST,
6975                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6976                   _clutter_boolean_handled_accumulator, NULL,
6977                   _clutter_marshal_BOOLEAN__BOXED,
6978                   G_TYPE_BOOLEAN, 1,
6979                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6980   /**
6981    * ClutterActor::key-press-event:
6982    * @actor: the actor which received the event
6983    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6984    *
6985    * The ::key-press-event signal is emitted each time a keyboard button
6986    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6987    *
6988    * Return value: %TRUE if the event has been handled by the actor,
6989    *   or %FALSE to continue the emission.
6990    *
6991    * Since: 0.6
6992    */
6993   actor_signals[KEY_PRESS_EVENT] =
6994     g_signal_new (I_("key-press-event"),
6995                   G_TYPE_FROM_CLASS (object_class),
6996                   G_SIGNAL_RUN_LAST,
6997                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6998                   _clutter_boolean_handled_accumulator, NULL,
6999                   _clutter_marshal_BOOLEAN__BOXED,
7000                   G_TYPE_BOOLEAN, 1,
7001                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7002   /**
7003    * ClutterActor::key-release-event:
7004    * @actor: the actor which received the event
7005    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7006    *
7007    * The ::key-release-event signal is emitted each time a keyboard button
7008    * is released while @actor has key focus (see
7009    * clutter_stage_set_key_focus()).
7010    *
7011    * Return value: %TRUE if the event has been handled by the actor,
7012    *   or %FALSE to continue the emission.
7013    *
7014    * Since: 0.6
7015    */
7016   actor_signals[KEY_RELEASE_EVENT] =
7017     g_signal_new (I_("key-release-event"),
7018                   G_TYPE_FROM_CLASS (object_class),
7019                   G_SIGNAL_RUN_LAST,
7020                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7021                   _clutter_boolean_handled_accumulator, NULL,
7022                   _clutter_marshal_BOOLEAN__BOXED,
7023                   G_TYPE_BOOLEAN, 1,
7024                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7025   /**
7026    * ClutterActor::motion-event:
7027    * @actor: the actor which received the event
7028    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7029    *
7030    * The ::motion-event signal is emitted each time the mouse pointer is
7031    * moved over @actor.
7032    *
7033    * Return value: %TRUE if the event has been handled by the actor,
7034    *   or %FALSE to continue the emission.
7035    *
7036    * Since: 0.6
7037    */
7038   actor_signals[MOTION_EVENT] =
7039     g_signal_new (I_("motion-event"),
7040                   G_TYPE_FROM_CLASS (object_class),
7041                   G_SIGNAL_RUN_LAST,
7042                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7043                   _clutter_boolean_handled_accumulator, NULL,
7044                   _clutter_marshal_BOOLEAN__BOXED,
7045                   G_TYPE_BOOLEAN, 1,
7046                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7047
7048   /**
7049    * ClutterActor::key-focus-in:
7050    * @actor: the actor which now has key focus
7051    *
7052    * The ::key-focus-in signal is emitted when @actor receives key focus.
7053    *
7054    * Since: 0.6
7055    */
7056   actor_signals[KEY_FOCUS_IN] =
7057     g_signal_new (I_("key-focus-in"),
7058                   G_TYPE_FROM_CLASS (object_class),
7059                   G_SIGNAL_RUN_LAST,
7060                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7061                   NULL, NULL,
7062                   _clutter_marshal_VOID__VOID,
7063                   G_TYPE_NONE, 0);
7064
7065   /**
7066    * ClutterActor::key-focus-out:
7067    * @actor: the actor which now has key focus
7068    *
7069    * The ::key-focus-out signal is emitted when @actor loses key focus.
7070    *
7071    * Since: 0.6
7072    */
7073   actor_signals[KEY_FOCUS_OUT] =
7074     g_signal_new (I_("key-focus-out"),
7075                   G_TYPE_FROM_CLASS (object_class),
7076                   G_SIGNAL_RUN_LAST,
7077                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7078                   NULL, NULL,
7079                   _clutter_marshal_VOID__VOID,
7080                   G_TYPE_NONE, 0);
7081
7082   /**
7083    * ClutterActor::enter-event:
7084    * @actor: the actor which the pointer has entered.
7085    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7086    *
7087    * The ::enter-event signal is emitted when the pointer enters the @actor
7088    *
7089    * Return value: %TRUE if the event has been handled by the actor,
7090    *   or %FALSE to continue the emission.
7091    *
7092    * Since: 0.6
7093    */
7094   actor_signals[ENTER_EVENT] =
7095     g_signal_new (I_("enter-event"),
7096                   G_TYPE_FROM_CLASS (object_class),
7097                   G_SIGNAL_RUN_LAST,
7098                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7099                   _clutter_boolean_handled_accumulator, NULL,
7100                   _clutter_marshal_BOOLEAN__BOXED,
7101                   G_TYPE_BOOLEAN, 1,
7102                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7103
7104   /**
7105    * ClutterActor::leave-event:
7106    * @actor: the actor which the pointer has left
7107    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7108    *
7109    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7110    *
7111    * Return value: %TRUE if the event has been handled by the actor,
7112    *   or %FALSE to continue the emission.
7113    *
7114    * Since: 0.6
7115    */
7116   actor_signals[LEAVE_EVENT] =
7117     g_signal_new (I_("leave-event"),
7118                   G_TYPE_FROM_CLASS (object_class),
7119                   G_SIGNAL_RUN_LAST,
7120                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7121                   _clutter_boolean_handled_accumulator, NULL,
7122                   _clutter_marshal_BOOLEAN__BOXED,
7123                   G_TYPE_BOOLEAN, 1,
7124                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7125
7126   /**
7127    * ClutterActor::captured-event:
7128    * @actor: the actor which received the signal
7129    * @event: a #ClutterEvent
7130    *
7131    * The ::captured-event signal is emitted when an event is captured
7132    * by Clutter. This signal will be emitted starting from the top-level
7133    * container (the #ClutterStage) to the actor which received the event
7134    * going down the hierarchy. This signal can be used to intercept every
7135    * event before the specialized events (like
7136    * ClutterActor::button-press-event or ::key-released-event) are
7137    * emitted.
7138    *
7139    * Return value: %TRUE if the event has been handled by the actor,
7140    *   or %FALSE to continue the emission.
7141    *
7142    * Since: 0.6
7143    */
7144   actor_signals[CAPTURED_EVENT] =
7145     g_signal_new (I_("captured-event"),
7146                   G_TYPE_FROM_CLASS (object_class),
7147                   G_SIGNAL_RUN_LAST,
7148                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7149                   _clutter_boolean_handled_accumulator, NULL,
7150                   _clutter_marshal_BOOLEAN__BOXED,
7151                   G_TYPE_BOOLEAN, 1,
7152                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7153
7154   /**
7155    * ClutterActor::paint:
7156    * @actor: the #ClutterActor that received the signal
7157    *
7158    * The ::paint signal is emitted each time an actor is being painted.
7159    *
7160    * Subclasses of #ClutterActor should override the class signal handler
7161    * and paint themselves in that function.
7162    *
7163    * It is possible to connect a handler to the ::paint signal in order
7164    * to set up some custom aspect of a paint.
7165    *
7166    * Since: 0.8
7167    */
7168   actor_signals[PAINT] =
7169     g_signal_new (I_("paint"),
7170                   G_TYPE_FROM_CLASS (object_class),
7171                   G_SIGNAL_RUN_LAST |
7172                   G_SIGNAL_NO_HOOKS,
7173                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7174                   NULL, NULL,
7175                   _clutter_marshal_VOID__VOID,
7176                   G_TYPE_NONE, 0);
7177   /**
7178    * ClutterActor::realize:
7179    * @actor: the #ClutterActor that received the signal
7180    *
7181    * The ::realize signal is emitted each time an actor is being
7182    * realized.
7183    *
7184    * Since: 0.8
7185    */
7186   actor_signals[REALIZE] =
7187     g_signal_new (I_("realize"),
7188                   G_TYPE_FROM_CLASS (object_class),
7189                   G_SIGNAL_RUN_LAST,
7190                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7191                   NULL, NULL,
7192                   _clutter_marshal_VOID__VOID,
7193                   G_TYPE_NONE, 0);
7194   /**
7195    * ClutterActor::unrealize:
7196    * @actor: the #ClutterActor that received the signal
7197    *
7198    * The ::unrealize signal is emitted each time an actor is being
7199    * unrealized.
7200    *
7201    * Since: 0.8
7202    */
7203   actor_signals[UNREALIZE] =
7204     g_signal_new (I_("unrealize"),
7205                   G_TYPE_FROM_CLASS (object_class),
7206                   G_SIGNAL_RUN_LAST,
7207                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7208                   NULL, NULL,
7209                   _clutter_marshal_VOID__VOID,
7210                   G_TYPE_NONE, 0);
7211
7212   /**
7213    * ClutterActor::pick:
7214    * @actor: the #ClutterActor that received the signal
7215    * @color: the #ClutterColor to be used when picking
7216    *
7217    * The ::pick signal is emitted each time an actor is being painted
7218    * in "pick mode". The pick mode is used to identify the actor during
7219    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7220    * The actor should paint its shape using the passed @pick_color.
7221    *
7222    * Subclasses of #ClutterActor should override the class signal handler
7223    * and paint themselves in that function.
7224    *
7225    * It is possible to connect a handler to the ::pick signal in order
7226    * to set up some custom aspect of a paint in pick mode.
7227    *
7228    * Since: 1.0
7229    */
7230   actor_signals[PICK] =
7231     g_signal_new (I_("pick"),
7232                   G_TYPE_FROM_CLASS (object_class),
7233                   G_SIGNAL_RUN_LAST,
7234                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7235                   NULL, NULL,
7236                   _clutter_marshal_VOID__BOXED,
7237                   G_TYPE_NONE, 1,
7238                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7239
7240   /**
7241    * ClutterActor::allocation-changed:
7242    * @actor: the #ClutterActor that emitted the signal
7243    * @box: a #ClutterActorBox with the new allocation
7244    * @flags: #ClutterAllocationFlags for the allocation
7245    *
7246    * The ::allocation-changed signal is emitted when the
7247    * #ClutterActor:allocation property changes. Usually, application
7248    * code should just use the notifications for the :allocation property
7249    * but if you want to track the allocation flags as well, for instance
7250    * to know whether the absolute origin of @actor changed, then you might
7251    * want use this signal instead.
7252    *
7253    * Since: 1.0
7254    */
7255   actor_signals[ALLOCATION_CHANGED] =
7256     g_signal_new (I_("allocation-changed"),
7257                   G_TYPE_FROM_CLASS (object_class),
7258                   G_SIGNAL_RUN_LAST,
7259                   0,
7260                   NULL, NULL,
7261                   _clutter_marshal_VOID__BOXED_FLAGS,
7262                   G_TYPE_NONE, 2,
7263                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7264                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7265
7266   /**
7267    * ClutterActor::transitions-completed:
7268    * @actor: a #ClutterActor
7269    *
7270    * The ::transitions-completed signal is emitted once all transitions
7271    * involving @actor are complete.
7272    *
7273    * Since: 1.10
7274    */
7275   actor_signals[TRANSITIONS_COMPLETED] =
7276     g_signal_new (I_("transitions-completed"),
7277                   G_TYPE_FROM_CLASS (object_class),
7278                   G_SIGNAL_RUN_LAST,
7279                   0,
7280                   NULL, NULL,
7281                   _clutter_marshal_VOID__VOID,
7282                   G_TYPE_NONE, 0);
7283 }
7284
7285 static void
7286 clutter_actor_init (ClutterActor *self)
7287 {
7288   ClutterActorPrivate *priv;
7289
7290   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7291
7292   priv->id = _clutter_context_acquire_id (self);
7293   priv->pick_id = -1;
7294
7295   priv->opacity = 0xff;
7296   priv->show_on_set_parent = TRUE;
7297
7298   priv->needs_width_request = TRUE;
7299   priv->needs_height_request = TRUE;
7300   priv->needs_allocation = TRUE;
7301
7302   priv->cached_width_age = 1;
7303   priv->cached_height_age = 1;
7304
7305   priv->opacity_override = -1;
7306   priv->enable_model_view_transform = TRUE;
7307
7308   /* Initialize an empty paint volume to start with */
7309   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7310   priv->last_paint_volume_valid = TRUE;
7311
7312   priv->transform_valid = FALSE;
7313
7314   /* the default is to stretch the content, to match the
7315    * current behaviour of basically all actors. also, it's
7316    * the easiest thing to compute.
7317    */
7318   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7319   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7320   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7321
7322   /* this flag will be set to TRUE if the actor gets a child
7323    * or if the [xy]-expand flags are explicitly set; until
7324    * then, the actor does not need to expand.
7325    *
7326    * this also allows us to avoid computing the expand flag
7327    * when building up a scene.
7328    */
7329   priv->needs_compute_expand = FALSE;
7330 }
7331
7332 /**
7333  * clutter_actor_new:
7334  *
7335  * Creates a new #ClutterActor.
7336  *
7337  * A newly created actor has a floating reference, which will be sunk
7338  * when it is added to another actor.
7339  *
7340  * Return value: (transfer full): the newly created #ClutterActor
7341  *
7342  * Since: 1.10
7343  */
7344 ClutterActor *
7345 clutter_actor_new (void)
7346 {
7347   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7348 }
7349
7350 /**
7351  * clutter_actor_destroy:
7352  * @self: a #ClutterActor
7353  *
7354  * Destroys an actor.  When an actor is destroyed, it will break any
7355  * references it holds to other objects.  If the actor is inside a
7356  * container, the actor will be removed.
7357  *
7358  * When you destroy a container, its children will be destroyed as well.
7359  *
7360  * Note: you cannot destroy the #ClutterStage returned by
7361  * clutter_stage_get_default().
7362  */
7363 void
7364 clutter_actor_destroy (ClutterActor *self)
7365 {
7366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7367
7368   g_object_ref (self);
7369
7370   /* avoid recursion while destroying */
7371   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7372     {
7373       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7374
7375       g_object_run_dispose (G_OBJECT (self));
7376
7377       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7378     }
7379
7380   g_object_unref (self);
7381 }
7382
7383 void
7384 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7385                                     ClutterPaintVolume *clip)
7386 {
7387   ClutterActorPrivate *priv = self->priv;
7388   ClutterPaintVolume *pv;
7389   gboolean clipped;
7390
7391   /* Remove queue entry early in the process, otherwise a new
7392      queue_redraw() during signal handling could put back this
7393      object in the stage redraw list (but the entry is freed as
7394      soon as we return from this function, causing a segfault
7395      later)
7396   */
7397   priv->queue_redraw_entry = NULL;
7398
7399   /* If we've been explicitly passed a clip volume then there's
7400    * nothing more to calculate, but otherwise the only thing we know
7401    * is that the change is constrained to the given actor.
7402    *
7403    * The idea is that if we know the paint volume for where the actor
7404    * was last drawn (in eye coordinates) and we also have the paint
7405    * volume for where it will be drawn next (in actor coordinates)
7406    * then if we queue a redraw for both these volumes that will cover
7407    * everything that needs to be redrawn to clear the old view and
7408    * show the latest view of the actor.
7409    *
7410    * Don't clip this redraw if we don't know what position we had for
7411    * the previous redraw since we don't know where to set the clip so
7412    * it will clear the actor as it is currently.
7413    */
7414   if (clip)
7415     {
7416       _clutter_actor_set_queue_redraw_clip (self, clip);
7417       clipped = TRUE;
7418     }
7419   else if (G_LIKELY (priv->last_paint_volume_valid))
7420     {
7421       pv = _clutter_actor_get_paint_volume_mutable (self);
7422       if (pv)
7423         {
7424           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7425
7426           /* make sure we redraw the actors old position... */
7427           _clutter_actor_set_queue_redraw_clip (stage,
7428                                                 &priv->last_paint_volume);
7429           _clutter_actor_signal_queue_redraw (stage, stage);
7430           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7431
7432           /* XXX: Ideally the redraw signal would take a clip volume
7433            * argument, but that would be an ABI break. Until we can
7434            * break the ABI we pass the argument out-of-band
7435            */
7436
7437           /* setup the clip for the actors new position... */
7438           _clutter_actor_set_queue_redraw_clip (self, pv);
7439           clipped = TRUE;
7440         }
7441       else
7442         clipped = FALSE;
7443     }
7444   else
7445     clipped = FALSE;
7446
7447   _clutter_actor_signal_queue_redraw (self, self);
7448
7449   /* Just in case anyone is manually firing redraw signals without
7450    * using the public queue_redraw() API we are careful to ensure that
7451    * our out-of-band clip member is cleared before returning...
7452    *
7453    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7454    */
7455   if (G_LIKELY (clipped))
7456     _clutter_actor_set_queue_redraw_clip (self, NULL);
7457 }
7458
7459 static void
7460 _clutter_actor_get_allocation_clip (ClutterActor *self,
7461                                     ClutterActorBox *clip)
7462 {
7463   ClutterActorBox allocation;
7464
7465   /* XXX: we don't care if we get an out of date allocation here
7466    * because clutter_actor_queue_redraw_with_clip knows to ignore
7467    * the clip if the actor's allocation is invalid.
7468    *
7469    * This is noted because clutter_actor_get_allocation_box does some
7470    * unnecessary work to support buggy code with a comment suggesting
7471    * that it could be changed later which would be good for this use
7472    * case!
7473    */
7474   clutter_actor_get_allocation_box (self, &allocation);
7475
7476   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7477    * actor's own coordinate space but the allocation is in parent
7478    * coordinates */
7479   clip->x1 = 0;
7480   clip->y1 = 0;
7481   clip->x2 = allocation.x2 - allocation.x1;
7482   clip->y2 = allocation.y2 - allocation.y1;
7483 }
7484
7485 void
7486 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7487                                   ClutterRedrawFlags  flags,
7488                                   ClutterPaintVolume *volume,
7489                                   ClutterEffect      *effect)
7490 {
7491   ClutterActorPrivate *priv = self->priv;
7492   ClutterPaintVolume allocation_pv;
7493   ClutterPaintVolume *pv;
7494   gboolean should_free_pv;
7495   ClutterActor *stage;
7496
7497   /* Here's an outline of the actor queue redraw mechanism:
7498    *
7499    * The process starts in one of the following two functions which
7500    * are wrappers for this function:
7501    * clutter_actor_queue_redraw
7502    * _clutter_actor_queue_redraw_with_clip
7503    *
7504    * additionally, an effect can queue a redraw by wrapping this
7505    * function in clutter_effect_queue_rerun
7506    *
7507    * This functions queues an entry in a list associated with the
7508    * stage which is a list of actors that queued a redraw while
7509    * updating the timelines, performing layouting and processing other
7510    * mainloop sources before the next paint starts.
7511    *
7512    * We aim to minimize the processing done at this point because
7513    * there is a good chance other events will happen while updating
7514    * the scenegraph that would invalidate any expensive work we might
7515    * otherwise try to do here. For example we don't try and resolve
7516    * the screen space bounding box of an actor at this stage so as to
7517    * minimize how much of the screen redraw because it's possible
7518    * something else will happen which will force a full redraw anyway.
7519    *
7520    * When all updates are complete and we come to paint the stage then
7521    * we iterate this list and actually emit the "queue-redraw" signals
7522    * for each of the listed actors which will bubble up to the stage
7523    * for each actor and at that point we will transform the actors
7524    * paint volume into screen coordinates to determine the clip region
7525    * for what needs to be redrawn in the next paint.
7526    *
7527    * Besides minimizing redundant work another reason for this
7528    * deferred design is that it's more likely we will be able to
7529    * determine the paint volume of an actor once we've finished
7530    * updating the scenegraph because its allocation should be up to
7531    * date. NB: If we can't determine an actors paint volume then we
7532    * can't automatically queue a clipped redraw which can make a big
7533    * difference to performance.
7534    *
7535    * So the control flow goes like this:
7536    * One of clutter_actor_queue_redraw,
7537    *        _clutter_actor_queue_redraw_with_clip
7538    *     or clutter_effect_queue_rerun
7539    *
7540    * then control moves to:
7541    *   _clutter_stage_queue_actor_redraw
7542    *
7543    * later during _clutter_stage_do_update, once relayouting is done
7544    * and the scenegraph has been updated we will call:
7545    * _clutter_stage_finish_queue_redraws
7546    *
7547    * _clutter_stage_finish_queue_redraws will call
7548    * _clutter_actor_finish_queue_redraw for each listed actor.
7549    * Note: actors *are* allowed to queue further redraws during this
7550    * process (considering clone actors or texture_new_from_actor which
7551    * respond to their source queueing a redraw by queuing a redraw
7552    * themselves). We repeat the process until the list is empty.
7553    *
7554    * This will result in the "queue-redraw" signal being fired for
7555    * each actor which will pass control to the default signal handler:
7556    * clutter_actor_real_queue_redraw
7557    *
7558    * This will bubble up to the stages handler:
7559    * clutter_stage_real_queue_redraw
7560    *
7561    * clutter_stage_real_queue_redraw will transform the actors paint
7562    * volume into screen space and add it as a clip region for the next
7563    * paint.
7564    */
7565
7566   /* ignore queueing a redraw for actors being destroyed */
7567   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7568     return;
7569
7570   stage = _clutter_actor_get_stage_internal (self);
7571
7572   /* Ignore queueing a redraw for actors not descended from a stage */
7573   if (stage == NULL)
7574     return;
7575
7576   /* ignore queueing a redraw on stages that are being destroyed */
7577   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7578     return;
7579
7580   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7581     {
7582       ClutterActorBox allocation_clip;
7583       ClutterVertex origin;
7584
7585       /* If the actor doesn't have a valid allocation then we will
7586        * queue a full stage redraw. */
7587       if (priv->needs_allocation)
7588         {
7589           /* NB: NULL denotes an undefined clip which will result in a
7590            * full redraw... */
7591           _clutter_actor_set_queue_redraw_clip (self, NULL);
7592           _clutter_actor_signal_queue_redraw (self, self);
7593           return;
7594         }
7595
7596       _clutter_paint_volume_init_static (&allocation_pv, self);
7597       pv = &allocation_pv;
7598
7599       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7600
7601       origin.x = allocation_clip.x1;
7602       origin.y = allocation_clip.y1;
7603       origin.z = 0;
7604       clutter_paint_volume_set_origin (pv, &origin);
7605       clutter_paint_volume_set_width (pv,
7606                                       allocation_clip.x2 - allocation_clip.x1);
7607       clutter_paint_volume_set_height (pv,
7608                                        allocation_clip.y2 -
7609                                        allocation_clip.y1);
7610       should_free_pv = TRUE;
7611     }
7612   else
7613     {
7614       pv = volume;
7615       should_free_pv = FALSE;
7616     }
7617
7618   self->priv->queue_redraw_entry =
7619     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7620                                        priv->queue_redraw_entry,
7621                                        self,
7622                                        pv);
7623
7624   if (should_free_pv)
7625     clutter_paint_volume_free (pv);
7626
7627   /* If this is the first redraw queued then we can directly use the
7628      effect parameter */
7629   if (!priv->is_dirty)
7630     priv->effect_to_redraw = effect;
7631   /* Otherwise we need to merge it with the existing effect parameter */
7632   else if (effect != NULL)
7633     {
7634       /* If there's already an effect then we need to use whichever is
7635          later in the chain of actors. Otherwise a full redraw has
7636          already been queued on the actor so we need to ignore the
7637          effect parameter */
7638       if (priv->effect_to_redraw != NULL)
7639         {
7640           if (priv->effects == NULL)
7641             g_warning ("Redraw queued with an effect that is "
7642                        "not applied to the actor");
7643           else
7644             {
7645               const GList *l;
7646
7647               for (l = _clutter_meta_group_peek_metas (priv->effects);
7648                    l != NULL;
7649                    l = l->next)
7650                 {
7651                   if (l->data == priv->effect_to_redraw ||
7652                       l->data == effect)
7653                     priv->effect_to_redraw = l->data;
7654                 }
7655             }
7656         }
7657     }
7658   else
7659     {
7660       /* If no effect is specified then we need to redraw the whole
7661          actor */
7662       priv->effect_to_redraw = NULL;
7663     }
7664
7665   priv->is_dirty = TRUE;
7666 }
7667
7668 /**
7669  * clutter_actor_queue_redraw:
7670  * @self: A #ClutterActor
7671  *
7672  * Queues up a redraw of an actor and any children. The redraw occurs
7673  * once the main loop becomes idle (after the current batch of events
7674  * has been processed, roughly).
7675  *
7676  * Applications rarely need to call this, as redraws are handled
7677  * automatically by modification functions.
7678  *
7679  * This function will not do anything if @self is not visible, or
7680  * if the actor is inside an invisible part of the scenegraph.
7681  *
7682  * Also be aware that painting is a NOP for actors with an opacity of
7683  * 0
7684  *
7685  * When you are implementing a custom actor you must queue a redraw
7686  * whenever some private state changes that will affect painting or
7687  * picking of your actor.
7688  */
7689 void
7690 clutter_actor_queue_redraw (ClutterActor *self)
7691 {
7692   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7693
7694   _clutter_actor_queue_redraw_full (self,
7695                                     0, /* flags */
7696                                     NULL, /* clip volume */
7697                                     NULL /* effect */);
7698 }
7699
7700 /*< private >
7701  * _clutter_actor_queue_redraw_with_clip:
7702  * @self: A #ClutterActor
7703  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7704  *   this queue redraw.
7705  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7706  *   redrawn or %NULL if you are just using a @flag to state your
7707  *   desired clipping.
7708  *
7709  * Queues up a clipped redraw of an actor and any children. The redraw
7710  * occurs once the main loop becomes idle (after the current batch of
7711  * events has been processed, roughly).
7712  *
7713  * If no flags are given the clip volume is defined by @volume
7714  * specified in actor coordinates and tells Clutter that only content
7715  * within this volume has been changed so Clutter can optionally
7716  * optimize the redraw.
7717  *
7718  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7719  * should be %NULL and this tells Clutter to use the actor's current
7720  * allocation as a clip box. This flag can only be used for 2D actors,
7721  * because any actor with depth may be projected outside its
7722  * allocation.
7723  *
7724  * Applications rarely need to call this, as redraws are handled
7725  * automatically by modification functions.
7726  *
7727  * This function will not do anything if @self is not visible, or if
7728  * the actor is inside an invisible part of the scenegraph.
7729  *
7730  * Also be aware that painting is a NOP for actors with an opacity of
7731  * 0
7732  *
7733  * When you are implementing a custom actor you must queue a redraw
7734  * whenever some private state changes that will affect painting or
7735  * picking of your actor.
7736  */
7737 void
7738 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7739                                        ClutterRedrawFlags  flags,
7740                                        ClutterPaintVolume *volume)
7741 {
7742   _clutter_actor_queue_redraw_full (self,
7743                                     flags, /* flags */
7744                                     volume, /* clip volume */
7745                                     NULL /* effect */);
7746 }
7747
7748 static void
7749 _clutter_actor_queue_only_relayout (ClutterActor *self)
7750 {
7751   ClutterActorPrivate *priv = self->priv;
7752
7753   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7754     return;
7755
7756   if (priv->needs_width_request &&
7757       priv->needs_height_request &&
7758       priv->needs_allocation)
7759     return; /* save some cpu cycles */
7760
7761 #if CLUTTER_ENABLE_DEBUG
7762   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7763     {
7764       g_warning ("The actor '%s' is currently inside an allocation "
7765                  "cycle; calling clutter_actor_queue_relayout() is "
7766                  "not recommended",
7767                  _clutter_actor_get_debug_name (self));
7768     }
7769 #endif /* CLUTTER_ENABLE_DEBUG */
7770
7771   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7772 }
7773
7774 /**
7775  * clutter_actor_queue_redraw_with_clip:
7776  * @self: a #ClutterActor
7777  * @clip: (allow-none): a rectangular clip region, or %NULL
7778  *
7779  * Queues a redraw on @self limited to a specific, actor-relative
7780  * rectangular area.
7781  *
7782  * If @clip is %NULL this function is equivalent to
7783  * clutter_actor_queue_redraw().
7784  *
7785  * Since: 1.10
7786  */
7787 void
7788 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7789                                       const cairo_rectangle_int_t *clip)
7790 {
7791   ClutterPaintVolume volume;
7792   ClutterVertex origin;
7793
7794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7795
7796   if (clip == NULL)
7797     {
7798       clutter_actor_queue_redraw (self);
7799       return;
7800     }
7801
7802   _clutter_paint_volume_init_static (&volume, self);
7803
7804   origin.x = clip->x;
7805   origin.y = clip->y;
7806   origin.z = 0.0f;
7807
7808   clutter_paint_volume_set_origin (&volume, &origin);
7809   clutter_paint_volume_set_width (&volume, clip->width);
7810   clutter_paint_volume_set_height (&volume, clip->height);
7811
7812   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7813
7814   clutter_paint_volume_free (&volume);
7815 }
7816
7817 /**
7818  * clutter_actor_queue_relayout:
7819  * @self: A #ClutterActor
7820  *
7821  * Indicates that the actor's size request or other layout-affecting
7822  * properties may have changed. This function is used inside #ClutterActor
7823  * subclass implementations, not by applications directly.
7824  *
7825  * Queueing a new layout automatically queues a redraw as well.
7826  *
7827  * Since: 0.8
7828  */
7829 void
7830 clutter_actor_queue_relayout (ClutterActor *self)
7831 {
7832   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7833
7834   _clutter_actor_queue_only_relayout (self);
7835   clutter_actor_queue_redraw (self);
7836 }
7837
7838 /**
7839  * clutter_actor_get_preferred_size:
7840  * @self: a #ClutterActor
7841  * @min_width_p: (out) (allow-none): return location for the minimum
7842  *   width, or %NULL
7843  * @min_height_p: (out) (allow-none): return location for the minimum
7844  *   height, or %NULL
7845  * @natural_width_p: (out) (allow-none): return location for the natural
7846  *   width, or %NULL
7847  * @natural_height_p: (out) (allow-none): return location for the natural
7848  *   height, or %NULL
7849  *
7850  * Computes the preferred minimum and natural size of an actor, taking into
7851  * account the actor's geometry management (either height-for-width
7852  * or width-for-height).
7853  *
7854  * The width and height used to compute the preferred height and preferred
7855  * width are the actor's natural ones.
7856  *
7857  * If you need to control the height for the preferred width, or the width for
7858  * the preferred height, you should use clutter_actor_get_preferred_width()
7859  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7860  * geometry management using the #ClutterActor:request-mode property.
7861  *
7862  * Since: 0.8
7863  */
7864 void
7865 clutter_actor_get_preferred_size (ClutterActor *self,
7866                                   gfloat       *min_width_p,
7867                                   gfloat       *min_height_p,
7868                                   gfloat       *natural_width_p,
7869                                   gfloat       *natural_height_p)
7870 {
7871   ClutterActorPrivate *priv;
7872   gfloat min_width, min_height;
7873   gfloat natural_width, natural_height;
7874
7875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7876
7877   priv = self->priv;
7878
7879   min_width = min_height = 0;
7880   natural_width = natural_height = 0;
7881
7882   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7883     {
7884       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7885       clutter_actor_get_preferred_width (self, -1,
7886                                          &min_width,
7887                                          &natural_width);
7888       clutter_actor_get_preferred_height (self, natural_width,
7889                                           &min_height,
7890                                           &natural_height);
7891     }
7892   else
7893     {
7894       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7895       clutter_actor_get_preferred_height (self, -1,
7896                                           &min_height,
7897                                           &natural_height);
7898       clutter_actor_get_preferred_width (self, natural_height,
7899                                          &min_width,
7900                                          &natural_width);
7901     }
7902
7903   if (min_width_p)
7904     *min_width_p = min_width;
7905
7906   if (min_height_p)
7907     *min_height_p = min_height;
7908
7909   if (natural_width_p)
7910     *natural_width_p = natural_width;
7911
7912   if (natural_height_p)
7913     *natural_height_p = natural_height;
7914 }
7915
7916 /*< private >
7917  * effective_align:
7918  * @align: a #ClutterActorAlign
7919  * @direction: a #ClutterTextDirection
7920  *
7921  * Retrieves the correct alignment depending on the text direction
7922  *
7923  * Return value: the effective alignment
7924  */
7925 static ClutterActorAlign
7926 effective_align (ClutterActorAlign    align,
7927                  ClutterTextDirection direction)
7928 {
7929   ClutterActorAlign res;
7930
7931   switch (align)
7932     {
7933     case CLUTTER_ACTOR_ALIGN_START:
7934       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7935           ? CLUTTER_ACTOR_ALIGN_END
7936           : CLUTTER_ACTOR_ALIGN_START;
7937       break;
7938
7939     case CLUTTER_ACTOR_ALIGN_END:
7940       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7941           ? CLUTTER_ACTOR_ALIGN_START
7942           : CLUTTER_ACTOR_ALIGN_END;
7943       break;
7944
7945     default:
7946       res = align;
7947       break;
7948     }
7949
7950   return res;
7951 }
7952
7953 /*< private >
7954  * _clutter_actor_get_effective_x_align:
7955  * @self: a #ClutterActor
7956  *
7957  * Retrieves the effective horizontal alignment, taking into
7958  * consideration the text direction of @self.
7959  *
7960  * Return value: the effective horizontal alignment
7961  */
7962 ClutterActorAlign
7963 _clutter_actor_get_effective_x_align (ClutterActor *self)
7964 {
7965   return effective_align (clutter_actor_get_x_align (self),
7966                           clutter_actor_get_text_direction (self));
7967 }
7968
7969 static inline void
7970 adjust_for_margin (float  margin_start,
7971                    float  margin_end,
7972                    float *minimum_size,
7973                    float *natural_size,
7974                    float *allocated_start,
7975                    float *allocated_end)
7976 {
7977   *minimum_size -= (margin_start + margin_end);
7978   *natural_size -= (margin_start + margin_end);
7979   *allocated_start += margin_start;
7980   *allocated_end -= margin_end;
7981 }
7982
7983 static inline void
7984 adjust_for_alignment (ClutterActorAlign  alignment,
7985                       float              natural_size,
7986                       float             *allocated_start,
7987                       float             *allocated_end)
7988 {
7989   float allocated_size = *allocated_end - *allocated_start;
7990
7991   switch (alignment)
7992     {
7993     case CLUTTER_ACTOR_ALIGN_FILL:
7994       /* do nothing */
7995       break;
7996
7997     case CLUTTER_ACTOR_ALIGN_START:
7998       /* keep start */
7999       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8000       break;
8001
8002     case CLUTTER_ACTOR_ALIGN_END:
8003       if (allocated_size > natural_size)
8004         {
8005           *allocated_start += (allocated_size - natural_size);
8006           *allocated_end = *allocated_start + natural_size;
8007         }
8008       break;
8009
8010     case CLUTTER_ACTOR_ALIGN_CENTER:
8011       if (allocated_size > natural_size)
8012         {
8013           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8014           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8015         }
8016       break;
8017     }
8018 }
8019
8020 /*< private >
8021  * clutter_actor_adjust_width:
8022  * @self: a #ClutterActor
8023  * @minimum_width: (inout): the actor's preferred minimum width, which
8024  *   will be adjusted depending on the margin
8025  * @natural_width: (inout): the actor's preferred natural width, which
8026  *   will be adjusted depending on the margin
8027  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8028  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8029  *
8030  * Adjusts the preferred and allocated position and size of an actor,
8031  * depending on the margin and alignment properties.
8032  */
8033 static void
8034 clutter_actor_adjust_width (ClutterActor *self,
8035                             gfloat       *minimum_width,
8036                             gfloat       *natural_width,
8037                             gfloat       *adjusted_x1,
8038                             gfloat       *adjusted_x2)
8039 {
8040   ClutterTextDirection text_dir;
8041   const ClutterLayoutInfo *info;
8042
8043   info = _clutter_actor_get_layout_info_or_defaults (self);
8044   text_dir = clutter_actor_get_text_direction (self);
8045
8046   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8047
8048   /* this will tweak natural_width to remove the margin, so that
8049    * adjust_for_alignment() will use the correct size
8050    */
8051   adjust_for_margin (info->margin.left, info->margin.right,
8052                      minimum_width, natural_width,
8053                      adjusted_x1, adjusted_x2);
8054
8055   adjust_for_alignment (effective_align (info->x_align, text_dir),
8056                         *natural_width,
8057                         adjusted_x1, adjusted_x2);
8058 }
8059
8060 /*< private >
8061  * clutter_actor_adjust_height:
8062  * @self: a #ClutterActor
8063  * @minimum_height: (inout): the actor's preferred minimum height, which
8064  *   will be adjusted depending on the margin
8065  * @natural_height: (inout): the actor's preferred natural height, which
8066  *   will be adjusted depending on the margin
8067  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8068  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8069  *
8070  * Adjusts the preferred and allocated position and size of an actor,
8071  * depending on the margin and alignment properties.
8072  */
8073 static void
8074 clutter_actor_adjust_height (ClutterActor *self,
8075                              gfloat       *minimum_height,
8076                              gfloat       *natural_height,
8077                              gfloat       *adjusted_y1,
8078                              gfloat       *adjusted_y2)
8079 {
8080   const ClutterLayoutInfo *info;
8081
8082   info = _clutter_actor_get_layout_info_or_defaults (self);
8083
8084   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8085
8086   /* this will tweak natural_height to remove the margin, so that
8087    * adjust_for_alignment() will use the correct size
8088    */
8089   adjust_for_margin (info->margin.top, info->margin.bottom,
8090                      minimum_height, natural_height,
8091                      adjusted_y1,
8092                      adjusted_y2);
8093
8094   /* we don't use effective_align() here, because text direction
8095    * only affects the horizontal axis
8096    */
8097   adjust_for_alignment (info->y_align,
8098                         *natural_height,
8099                         adjusted_y1,
8100                         adjusted_y2);
8101
8102 }
8103
8104 /* looks for a cached size request for this for_size. If not
8105  * found, returns the oldest entry so it can be overwritten */
8106 static gboolean
8107 _clutter_actor_get_cached_size_request (gfloat         for_size,
8108                                         SizeRequest   *cached_size_requests,
8109                                         SizeRequest  **result)
8110 {
8111   guint i;
8112
8113   *result = &cached_size_requests[0];
8114
8115   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8116     {
8117       SizeRequest *sr;
8118
8119       sr = &cached_size_requests[i];
8120
8121       if (sr->age > 0 &&
8122           sr->for_size == for_size)
8123         {
8124           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8125           *result = sr;
8126           return TRUE;
8127         }
8128       else if (sr->age < (*result)->age)
8129         {
8130           *result = sr;
8131         }
8132     }
8133
8134   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8135
8136   return FALSE;
8137 }
8138
8139 /**
8140  * clutter_actor_get_preferred_width:
8141  * @self: A #ClutterActor
8142  * @for_height: available height when computing the preferred width,
8143  *   or a negative value to indicate that no height is defined
8144  * @min_width_p: (out) (allow-none): return location for minimum width,
8145  *   or %NULL
8146  * @natural_width_p: (out) (allow-none): return location for the natural
8147  *   width, or %NULL
8148  *
8149  * Computes the requested minimum and natural widths for an actor,
8150  * optionally depending on the specified height, or if they are
8151  * already computed, returns the cached values.
8152  *
8153  * An actor may not get its request - depending on the layout
8154  * manager that's in effect.
8155  *
8156  * A request should not incorporate the actor's scale or anchor point;
8157  * those transformations do not affect layout, only rendering.
8158  *
8159  * Since: 0.8
8160  */
8161 void
8162 clutter_actor_get_preferred_width (ClutterActor *self,
8163                                    gfloat        for_height,
8164                                    gfloat       *min_width_p,
8165                                    gfloat       *natural_width_p)
8166 {
8167   float request_min_width, request_natural_width;
8168   SizeRequest *cached_size_request;
8169   const ClutterLayoutInfo *info;
8170   ClutterActorPrivate *priv;
8171   gboolean found_in_cache;
8172
8173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8174
8175   priv = self->priv;
8176
8177   info = _clutter_actor_get_layout_info_or_defaults (self);
8178
8179   /* we shortcircuit the case of a fixed size set using set_width() */
8180   if (priv->min_width_set && priv->natural_width_set)
8181     {
8182       if (min_width_p != NULL)
8183         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8184
8185       if (natural_width_p != NULL)
8186         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8187
8188       return;
8189     }
8190
8191   /* the remaining cases are:
8192    *
8193    *   - either min_width or natural_width have been set
8194    *   - neither min_width or natural_width have been set
8195    *
8196    * in both cases, we go through the cache (and through the actor in case
8197    * of cache misses) and determine the authoritative value depending on
8198    * the *_set flags.
8199    */
8200
8201   if (!priv->needs_width_request)
8202     {
8203       found_in_cache =
8204         _clutter_actor_get_cached_size_request (for_height,
8205                                                 priv->width_requests,
8206                                                 &cached_size_request);
8207     }
8208   else
8209     {
8210       /* if the actor needs a width request we use the first slot */
8211       found_in_cache = FALSE;
8212       cached_size_request = &priv->width_requests[0];
8213     }
8214
8215   if (!found_in_cache)
8216     {
8217       gfloat minimum_width, natural_width;
8218       ClutterActorClass *klass;
8219
8220       minimum_width = natural_width = 0;
8221
8222       /* adjust for the margin */
8223       if (for_height >= 0)
8224         {
8225           for_height -= (info->margin.top + info->margin.bottom);
8226           if (for_height < 0)
8227             for_height = 0;
8228         }
8229
8230       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8231
8232       klass = CLUTTER_ACTOR_GET_CLASS (self);
8233       klass->get_preferred_width (self, for_height,
8234                                   &minimum_width,
8235                                   &natural_width);
8236
8237       /* adjust for the margin */
8238       minimum_width += (info->margin.left + info->margin.right);
8239       natural_width += (info->margin.left + info->margin.right);
8240
8241       /* Due to accumulated float errors, it's better not to warn
8242        * on this, but just fix it.
8243        */
8244       if (natural_width < minimum_width)
8245         natural_width = minimum_width;
8246
8247       cached_size_request->min_size = minimum_width;
8248       cached_size_request->natural_size = natural_width;
8249       cached_size_request->for_size = for_height;
8250       cached_size_request->age = priv->cached_width_age;
8251
8252       priv->cached_width_age += 1;
8253       priv->needs_width_request = FALSE;
8254     }
8255
8256   if (!priv->min_width_set)
8257     request_min_width = cached_size_request->min_size;
8258   else
8259     request_min_width = info->minimum.width;
8260
8261   if (!priv->natural_width_set)
8262     request_natural_width = cached_size_request->natural_size;
8263   else
8264     request_natural_width = info->natural.width;
8265
8266   if (min_width_p)
8267     *min_width_p = request_min_width;
8268
8269   if (natural_width_p)
8270     *natural_width_p = request_natural_width;
8271 }
8272
8273 /**
8274  * clutter_actor_get_preferred_height:
8275  * @self: A #ClutterActor
8276  * @for_width: available width to assume in computing desired height,
8277  *   or a negative value to indicate that no width is defined
8278  * @min_height_p: (out) (allow-none): return location for minimum height,
8279  *   or %NULL
8280  * @natural_height_p: (out) (allow-none): return location for natural
8281  *   height, or %NULL
8282  *
8283  * Computes the requested minimum and natural heights for an actor,
8284  * or if they are already computed, returns the cached values.
8285  *
8286  * An actor may not get its request - depending on the layout
8287  * manager that's in effect.
8288  *
8289  * A request should not incorporate the actor's scale or anchor point;
8290  * those transformations do not affect layout, only rendering.
8291  *
8292  * Since: 0.8
8293  */
8294 void
8295 clutter_actor_get_preferred_height (ClutterActor *self,
8296                                     gfloat        for_width,
8297                                     gfloat       *min_height_p,
8298                                     gfloat       *natural_height_p)
8299 {
8300   float request_min_height, request_natural_height;
8301   SizeRequest *cached_size_request;
8302   const ClutterLayoutInfo *info;
8303   ClutterActorPrivate *priv;
8304   gboolean found_in_cache;
8305
8306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8307
8308   priv = self->priv;
8309
8310   info = _clutter_actor_get_layout_info_or_defaults (self);
8311
8312   /* we shortcircuit the case of a fixed size set using set_height() */
8313   if (priv->min_height_set && priv->natural_height_set)
8314     {
8315       if (min_height_p != NULL)
8316         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8317
8318       if (natural_height_p != NULL)
8319         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8320
8321       return;
8322     }
8323
8324   /* the remaining cases are:
8325    *
8326    *   - either min_height or natural_height have been set
8327    *   - neither min_height or natural_height have been set
8328    *
8329    * in both cases, we go through the cache (and through the actor in case
8330    * of cache misses) and determine the authoritative value depending on
8331    * the *_set flags.
8332    */
8333
8334   if (!priv->needs_height_request)
8335     {
8336       found_in_cache =
8337         _clutter_actor_get_cached_size_request (for_width,
8338                                                 priv->height_requests,
8339                                                 &cached_size_request);
8340     }
8341   else
8342     {
8343       found_in_cache = FALSE;
8344       cached_size_request = &priv->height_requests[0];
8345     }
8346
8347   if (!found_in_cache)
8348     {
8349       gfloat minimum_height, natural_height;
8350       ClutterActorClass *klass;
8351
8352       minimum_height = natural_height = 0;
8353
8354       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8355
8356       /* adjust for margin */
8357       if (for_width >= 0)
8358         {
8359           for_width -= (info->margin.left + info->margin.right);
8360           if (for_width < 0)
8361             for_width = 0;
8362         }
8363
8364       klass = CLUTTER_ACTOR_GET_CLASS (self);
8365       klass->get_preferred_height (self, for_width,
8366                                    &minimum_height,
8367                                    &natural_height);
8368
8369       /* adjust for margin */
8370       minimum_height += (info->margin.top + info->margin.bottom);
8371       natural_height += (info->margin.top + info->margin.bottom);
8372
8373       /* Due to accumulated float errors, it's better not to warn
8374        * on this, but just fix it.
8375        */
8376       if (natural_height < minimum_height)
8377         natural_height = minimum_height;
8378
8379       cached_size_request->min_size = minimum_height;
8380       cached_size_request->natural_size = natural_height;
8381       cached_size_request->for_size = for_width;
8382       cached_size_request->age = priv->cached_height_age;
8383
8384       priv->cached_height_age += 1;
8385       priv->needs_height_request = FALSE;
8386     }
8387
8388   if (!priv->min_height_set)
8389     request_min_height = cached_size_request->min_size;
8390   else
8391     request_min_height = info->minimum.height;
8392
8393   if (!priv->natural_height_set)
8394     request_natural_height = cached_size_request->natural_size;
8395   else
8396     request_natural_height = info->natural.height;
8397
8398   if (min_height_p)
8399     *min_height_p = request_min_height;
8400
8401   if (natural_height_p)
8402     *natural_height_p = request_natural_height;
8403 }
8404
8405 /**
8406  * clutter_actor_get_allocation_box:
8407  * @self: A #ClutterActor
8408  * @box: (out): the function fills this in with the actor's allocation
8409  *
8410  * Gets the layout box an actor has been assigned. The allocation can
8411  * only be assumed valid inside a paint() method; anywhere else, it
8412  * may be out-of-date.
8413  *
8414  * An allocation does not incorporate the actor's scale or anchor point;
8415  * those transformations do not affect layout, only rendering.
8416  *
8417  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8418  * of functions inside the implementation of the get_preferred_width()
8419  * or get_preferred_height() virtual functions.</note>
8420  *
8421  * Since: 0.8
8422  */
8423 void
8424 clutter_actor_get_allocation_box (ClutterActor    *self,
8425                                   ClutterActorBox *box)
8426 {
8427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8428
8429   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8430    * which limits calling get_allocation to inside paint() basically; or
8431    * we can 2) force a layout, which could be expensive if someone calls
8432    * get_allocation somewhere silly; or we can 3) just return the latest
8433    * value, allowing it to be out-of-date, and assume people know what
8434    * they are doing.
8435    *
8436    * The least-surprises approach that keeps existing code working is
8437    * likely to be 2). People can end up doing some inefficient things,
8438    * though, and in general code that requires 2) is probably broken.
8439    */
8440
8441   /* this implements 2) */
8442   if (G_UNLIKELY (self->priv->needs_allocation))
8443     {
8444       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8445
8446       /* do not queue a relayout on an unparented actor */
8447       if (stage)
8448         _clutter_stage_maybe_relayout (stage);
8449     }
8450
8451   /* commenting out the code above and just keeping this assigment
8452    * implements 3)
8453    */
8454   *box = self->priv->allocation;
8455 }
8456
8457 /**
8458  * clutter_actor_get_allocation_geometry:
8459  * @self: A #ClutterActor
8460  * @geom: (out): allocation geometry in pixels
8461  *
8462  * Gets the layout box an actor has been assigned.  The allocation can
8463  * only be assumed valid inside a paint() method; anywhere else, it
8464  * may be out-of-date.
8465  *
8466  * An allocation does not incorporate the actor's scale or anchor point;
8467  * those transformations do not affect layout, only rendering.
8468  *
8469  * The returned rectangle is in pixels.
8470  *
8471  * Since: 0.8
8472  */
8473 void
8474 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8475                                        ClutterGeometry *geom)
8476 {
8477   ClutterActorBox box;
8478
8479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8480   g_return_if_fail (geom != NULL);
8481
8482   clutter_actor_get_allocation_box (self, &box);
8483
8484   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8485   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8486   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8487   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8488 }
8489
8490 static void
8491 clutter_actor_update_constraints (ClutterActor    *self,
8492                                   ClutterActorBox *allocation)
8493 {
8494   ClutterActorPrivate *priv = self->priv;
8495   const GList *constraints, *l;
8496
8497   if (priv->constraints == NULL)
8498     return;
8499
8500   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8501   for (l = constraints; l != NULL; l = l->next)
8502     {
8503       ClutterConstraint *constraint = l->data;
8504       ClutterActorMeta *meta = l->data;
8505
8506       if (clutter_actor_meta_get_enabled (meta))
8507         {
8508           _clutter_constraint_update_allocation (constraint,
8509                                                  self,
8510                                                  allocation);
8511
8512           CLUTTER_NOTE (LAYOUT,
8513                         "Allocation of '%s' after constraint '%s': "
8514                         "{ %.2f, %.2f, %.2f, %.2f }",
8515                         _clutter_actor_get_debug_name (self),
8516                         _clutter_actor_meta_get_debug_name (meta),
8517                         allocation->x1,
8518                         allocation->y1,
8519                         allocation->x2,
8520                         allocation->y2);
8521         }
8522     }
8523 }
8524
8525 /*< private >
8526  * clutter_actor_adjust_allocation:
8527  * @self: a #ClutterActor
8528  * @allocation: (inout): the allocation to adjust
8529  *
8530  * Adjusts the passed allocation box taking into account the actor's
8531  * layout information, like alignment, expansion, and margin.
8532  */
8533 static void
8534 clutter_actor_adjust_allocation (ClutterActor    *self,
8535                                  ClutterActorBox *allocation)
8536 {
8537   ClutterActorBox adj_allocation;
8538   float alloc_width, alloc_height;
8539   float min_width, min_height;
8540   float nat_width, nat_height;
8541   ClutterRequestMode req_mode;
8542
8543   adj_allocation = *allocation;
8544
8545   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8546
8547   /* we want to hit the cache, so we use the public API */
8548   req_mode = clutter_actor_get_request_mode (self);
8549
8550   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8551     {
8552       clutter_actor_get_preferred_width (self, -1,
8553                                          &min_width,
8554                                          &nat_width);
8555       clutter_actor_get_preferred_height (self, alloc_width,
8556                                           &min_height,
8557                                           &nat_height);
8558     }
8559   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8560     {
8561       clutter_actor_get_preferred_height (self, -1,
8562                                           &min_height,
8563                                           &nat_height);
8564       clutter_actor_get_preferred_height (self, alloc_height,
8565                                           &min_width,
8566                                           &nat_width);
8567     }
8568
8569 #ifdef CLUTTER_ENABLE_DEBUG
8570   /* warn about underallocations */
8571   if (_clutter_diagnostic_enabled () &&
8572       (floorf (min_width - alloc_width) > 0 ||
8573        floorf (min_height - alloc_height) > 0))
8574     {
8575       ClutterActor *parent = clutter_actor_get_parent (self);
8576
8577       /* the only actors that are allowed to be underallocated are the Stage,
8578        * as it doesn't have an implicit size, and Actors that specifically
8579        * told us that they want to opt-out from layout control mechanisms
8580        * through the NO_LAYOUT escape hatch.
8581        */
8582       if (parent != NULL &&
8583           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8584         {
8585           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8586                      "of %.2f x %.2f from its parent actor '%s', but its "
8587                      "requested minimum size is of %.2f x %.2f",
8588                      _clutter_actor_get_debug_name (self),
8589                      alloc_width, alloc_height,
8590                      _clutter_actor_get_debug_name (parent),
8591                      min_width, min_height);
8592         }
8593     }
8594 #endif
8595
8596   clutter_actor_adjust_width (self,
8597                               &min_width,
8598                               &nat_width,
8599                               &adj_allocation.x1,
8600                               &adj_allocation.x2);
8601
8602   clutter_actor_adjust_height (self,
8603                                &min_height,
8604                                &nat_height,
8605                                &adj_allocation.y1,
8606                                &adj_allocation.y2);
8607
8608   /* we maintain the invariant that an allocation cannot be adjusted
8609    * to be outside the parent-given box
8610    */
8611   if (adj_allocation.x1 < allocation->x1 ||
8612       adj_allocation.y1 < allocation->y1 ||
8613       adj_allocation.x2 > allocation->x2 ||
8614       adj_allocation.y2 > allocation->y2)
8615     {
8616       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8617                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8618                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8619                  _clutter_actor_get_debug_name (self),
8620                  adj_allocation.x1, adj_allocation.y1,
8621                  adj_allocation.x2 - adj_allocation.x1,
8622                  adj_allocation.y2 - adj_allocation.y1,
8623                  allocation->x1, allocation->y1,
8624                  allocation->x2 - allocation->x1,
8625                  allocation->y2 - allocation->y1);
8626       return;
8627     }
8628
8629   *allocation = adj_allocation;
8630 }
8631
8632 /**
8633  * clutter_actor_allocate:
8634  * @self: A #ClutterActor
8635  * @box: new allocation of the actor, in parent-relative coordinates
8636  * @flags: flags that control the allocation
8637  *
8638  * Called by the parent of an actor to assign the actor its size.
8639  * Should never be called by applications (except when implementing
8640  * a container or layout manager).
8641  *
8642  * Actors can know from their allocation box whether they have moved
8643  * with respect to their parent actor. The @flags parameter describes
8644  * additional information about the allocation, for instance whether
8645  * the parent has moved with respect to the stage, for example because
8646  * a grandparent's origin has moved.
8647  *
8648  * Since: 0.8
8649  */
8650 void
8651 clutter_actor_allocate (ClutterActor           *self,
8652                         const ClutterActorBox  *box,
8653                         ClutterAllocationFlags  flags)
8654 {
8655   ClutterActorPrivate *priv;
8656   ClutterActorClass *klass;
8657   ClutterActorBox old_allocation, real_allocation;
8658   gboolean origin_changed, child_moved, size_changed;
8659   gboolean stage_allocation_changed;
8660
8661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8662   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8663     {
8664       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8665                  "which isn't a descendent of the stage!\n",
8666                  self, _clutter_actor_get_debug_name (self));
8667       return;
8668     }
8669
8670   priv = self->priv;
8671
8672   old_allocation = priv->allocation;
8673   real_allocation = *box;
8674
8675   /* constraints are allowed to modify the allocation only here; we do
8676    * this prior to all the other checks so that we can bail out if the
8677    * allocation did not change
8678    */
8679   clutter_actor_update_constraints (self, &real_allocation);
8680
8681   /* adjust the allocation depending on the align/margin properties */
8682   clutter_actor_adjust_allocation (self, &real_allocation);
8683
8684   if (real_allocation.x2 < real_allocation.x1 ||
8685       real_allocation.y2 < real_allocation.y1)
8686     {
8687       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8688                  _clutter_actor_get_debug_name (self),
8689                  real_allocation.x2 - real_allocation.x1,
8690                  real_allocation.y2 - real_allocation.y1);
8691     }
8692
8693   /* we allow 0-sized actors, but not negative-sized ones */
8694   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8695   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8696
8697   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8698
8699   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8700                  real_allocation.y1 != old_allocation.y1);
8701
8702   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8703                   real_allocation.y2 != old_allocation.y2);
8704
8705   if (origin_changed || child_moved || size_changed)
8706     stage_allocation_changed = TRUE;
8707   else
8708     stage_allocation_changed = FALSE;
8709
8710   /* If we get an allocation "out of the blue"
8711    * (we did not queue relayout), then we want to
8712    * ignore it. But if we have needs_allocation set,
8713    * we want to guarantee that allocate() virtual
8714    * method is always called, i.e. that queue_relayout()
8715    * always results in an allocate() invocation on
8716    * an actor.
8717    *
8718    * The optimization here is to avoid re-allocating
8719    * actors that did not queue relayout and were
8720    * not moved.
8721    */
8722   if (!priv->needs_allocation && !stage_allocation_changed)
8723     {
8724       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8725       return;
8726     }
8727
8728   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8729    * clutter_actor_allocate(), it indicates whether the parent has its
8730    * absolute origin moved; when passed in to ClutterActor::allocate()
8731    * virtual method though, it indicates whether the child has its
8732    * absolute origin moved.  So we set it when child_moved is TRUE
8733    */
8734   if (child_moved)
8735     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8736
8737   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8738
8739   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8740                 _clutter_actor_get_debug_name (self));
8741
8742   klass = CLUTTER_ACTOR_GET_CLASS (self);
8743   klass->allocate (self, &real_allocation, flags);
8744
8745   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8746
8747   if (stage_allocation_changed)
8748     clutter_actor_queue_redraw (self);
8749 }
8750
8751 /**
8752  * clutter_actor_set_allocation:
8753  * @self: a #ClutterActor
8754  * @box: a #ClutterActorBox
8755  * @flags: allocation flags
8756  *
8757  * Stores the allocation of @self as defined by @box.
8758  *
8759  * This function can only be called from within the implementation of
8760  * the #ClutterActorClass.allocate() virtual function.
8761  *
8762  * The allocation should have been adjusted to take into account constraints,
8763  * alignment, and margin properties. If you are implementing a #ClutterActor
8764  * subclass that provides its own layout management policy for its children
8765  * instead of using a #ClutterLayoutManager delegate, you should not call
8766  * this function on the children of @self; instead, you should call
8767  * clutter_actor_allocate(), which will adjust the allocation box for
8768  * you.
8769  *
8770  * This function should only be used by subclasses of #ClutterActor
8771  * that wish to store their allocation but cannot chain up to the
8772  * parent's implementation; the default implementation of the
8773  * #ClutterActorClass.allocate() virtual function will call this
8774  * function.
8775  *
8776  * It is important to note that, while chaining up was the recommended
8777  * behaviour for #ClutterActor subclasses prior to the introduction of
8778  * this function, it is recommended to call clutter_actor_set_allocation()
8779  * instead.
8780  *
8781  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8782  * to handle the allocation of its children, this function will call
8783  * the clutter_layout_manager_allocate() function only if the
8784  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8785  * expected that the subclass will call clutter_layout_manager_allocate()
8786  * by itself. For instance, the following code:
8787  *
8788  * |[
8789  * static void
8790  * my_actor_allocate (ClutterActor *actor,
8791  *                    const ClutterActorBox *allocation,
8792  *                    ClutterAllocationFlags flags)
8793  * {
8794  *   ClutterActorBox new_alloc;
8795  *   ClutterAllocationFlags new_flags;
8796  *
8797  *   adjust_allocation (allocation, &amp;new_alloc);
8798  *
8799  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8800  *
8801  *   /&ast; this will use the layout manager set on the actor &ast;/
8802  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8803  * }
8804  * ]|
8805  *
8806  * is equivalent to this:
8807  *
8808  * |[
8809  * static void
8810  * my_actor_allocate (ClutterActor *actor,
8811  *                    const ClutterActorBox *allocation,
8812  *                    ClutterAllocationFlags flags)
8813  * {
8814  *   ClutterLayoutManager *layout;
8815  *   ClutterActorBox new_alloc;
8816  *
8817  *   adjust_allocation (allocation, &amp;new_alloc);
8818  *
8819  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8820  *
8821  *   layout = clutter_actor_get_layout_manager (actor);
8822  *   clutter_layout_manager_allocate (layout,
8823  *                                    CLUTTER_CONTAINER (actor),
8824  *                                    &amp;new_alloc,
8825  *                                    flags);
8826  * }
8827  * ]|
8828  *
8829  * Since: 1.10
8830  */
8831 void
8832 clutter_actor_set_allocation (ClutterActor           *self,
8833                               const ClutterActorBox  *box,
8834                               ClutterAllocationFlags  flags)
8835 {
8836   ClutterActorPrivate *priv;
8837   gboolean changed;
8838
8839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8840   g_return_if_fail (box != NULL);
8841
8842   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8843     {
8844       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8845                   "can only be called from within the implementation of "
8846                   "the ClutterActor::allocate() virtual function.");
8847       return;
8848     }
8849
8850   priv = self->priv;
8851
8852   g_object_freeze_notify (G_OBJECT (self));
8853
8854   changed = clutter_actor_set_allocation_internal (self, box, flags);
8855
8856   /* we allocate our children before we notify changes in our geometry,
8857    * so that people connecting to properties will be able to get valid
8858    * data out of the sub-tree of the scene graph that has this actor at
8859    * the root.
8860    */
8861   clutter_actor_maybe_layout_children (self, box, flags);
8862
8863   if (changed)
8864     {
8865       ClutterActorBox signal_box = priv->allocation;
8866       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8867
8868       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8869                      &signal_box,
8870                      signal_flags);
8871     }
8872
8873   g_object_thaw_notify (G_OBJECT (self));
8874 }
8875
8876 /**
8877  * clutter_actor_set_geometry:
8878  * @self: A #ClutterActor
8879  * @geometry: A #ClutterGeometry
8880  *
8881  * Sets the actor's fixed position and forces its minimum and natural
8882  * size, in pixels. This means the untransformed actor will have the
8883  * given geometry. This is the same as calling clutter_actor_set_position()
8884  * and clutter_actor_set_size().
8885  *
8886  * Deprecated: 1.10: Use clutter_actor_set_position() and
8887  *   clutter_actor_set_size() instead.
8888  */
8889 void
8890 clutter_actor_set_geometry (ClutterActor          *self,
8891                             const ClutterGeometry *geometry)
8892 {
8893   g_object_freeze_notify (G_OBJECT (self));
8894
8895   clutter_actor_set_position (self, geometry->x, geometry->y);
8896   clutter_actor_set_size (self, geometry->width, geometry->height);
8897
8898   g_object_thaw_notify (G_OBJECT (self));
8899 }
8900
8901 /**
8902  * clutter_actor_get_geometry:
8903  * @self: A #ClutterActor
8904  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8905  *
8906  * Gets the size and position of an actor relative to its parent
8907  * actor. This is the same as calling clutter_actor_get_position() and
8908  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8909  * requested size and position if the actor's allocation is invalid.
8910  *
8911  * Deprecated: 1.10: Use clutter_actor_get_position() and
8912  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8913  *   instead.
8914  */
8915 void
8916 clutter_actor_get_geometry (ClutterActor    *self,
8917                             ClutterGeometry *geometry)
8918 {
8919   gfloat x, y, width, height;
8920
8921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8922   g_return_if_fail (geometry != NULL);
8923
8924   clutter_actor_get_position (self, &x, &y);
8925   clutter_actor_get_size (self, &width, &height);
8926
8927   geometry->x = (int) x;
8928   geometry->y = (int) y;
8929   geometry->width = (int) width;
8930   geometry->height = (int) height;
8931 }
8932
8933 /**
8934  * clutter_actor_set_position:
8935  * @self: A #ClutterActor
8936  * @x: New left position of actor in pixels.
8937  * @y: New top position of actor in pixels.
8938  *
8939  * Sets the actor's fixed position in pixels relative to any parent
8940  * actor.
8941  *
8942  * If a layout manager is in use, this position will override the
8943  * layout manager and force a fixed position.
8944  */
8945 void
8946 clutter_actor_set_position (ClutterActor *self,
8947                             gfloat        x,
8948                             gfloat        y)
8949 {
8950   ClutterPoint new_position;
8951
8952   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8953
8954   clutter_point_init (&new_position, x, y);
8955
8956   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8957     {
8958       ClutterPoint cur_position;
8959
8960       cur_position.x = clutter_actor_get_x (self);
8961       cur_position.y = clutter_actor_get_y (self);
8962
8963       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8964                                         &cur_position,
8965                                         &new_position);
8966     }
8967   else
8968     _clutter_actor_update_transition (self,
8969                                       obj_props[PROP_POSITION],
8970                                       &new_position);
8971
8972   clutter_actor_queue_relayout (self);
8973 }
8974
8975 /**
8976  * clutter_actor_get_fixed_position_set:
8977  * @self: A #ClutterActor
8978  *
8979  * Checks whether an actor has a fixed position set (and will thus be
8980  * unaffected by any layout manager).
8981  *
8982  * Return value: %TRUE if the fixed position is set on the actor
8983  *
8984  * Since: 0.8
8985  */
8986 gboolean
8987 clutter_actor_get_fixed_position_set (ClutterActor *self)
8988 {
8989   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8990
8991   return self->priv->position_set;
8992 }
8993
8994 /**
8995  * clutter_actor_set_fixed_position_set:
8996  * @self: A #ClutterActor
8997  * @is_set: whether to use fixed position
8998  *
8999  * Sets whether an actor has a fixed position set (and will thus be
9000  * unaffected by any layout manager).
9001  *
9002  * Since: 0.8
9003  */
9004 void
9005 clutter_actor_set_fixed_position_set (ClutterActor *self,
9006                                       gboolean      is_set)
9007 {
9008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9009
9010   if (self->priv->position_set == (is_set != FALSE))
9011     return;
9012
9013   self->priv->position_set = is_set != FALSE;
9014   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9015
9016   clutter_actor_queue_relayout (self);
9017 }
9018
9019 /**
9020  * clutter_actor_move_by:
9021  * @self: A #ClutterActor
9022  * @dx: Distance to move Actor on X axis.
9023  * @dy: Distance to move Actor on Y axis.
9024  *
9025  * Moves an actor by the specified distance relative to its current
9026  * position in pixels.
9027  *
9028  * This function modifies the fixed position of an actor and thus removes
9029  * it from any layout management. Another way to move an actor is with an
9030  * anchor point, see clutter_actor_set_anchor_point().
9031  *
9032  * Since: 0.2
9033  */
9034 void
9035 clutter_actor_move_by (ClutterActor *self,
9036                        gfloat        dx,
9037                        gfloat        dy)
9038 {
9039   const ClutterLayoutInfo *info;
9040   gfloat x, y;
9041
9042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9043
9044   info = _clutter_actor_get_layout_info_or_defaults (self);
9045   x = info->fixed_pos.x;
9046   y = info->fixed_pos.y;
9047
9048   clutter_actor_set_position (self, x + dx, y + dy);
9049 }
9050
9051 static void
9052 clutter_actor_set_min_width (ClutterActor *self,
9053                              gfloat        min_width)
9054 {
9055   ClutterActorPrivate *priv = self->priv;
9056   ClutterActorBox old = { 0, };
9057   ClutterLayoutInfo *info;
9058
9059   /* if we are setting the size on a top-level actor and the
9060    * backend only supports static top-levels (e.g. framebuffers)
9061    * then we ignore the passed value and we override it with
9062    * the stage implementation's preferred size.
9063    */
9064   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9065       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9066     return;
9067
9068   info = _clutter_actor_get_layout_info (self);
9069
9070   if (priv->min_width_set && min_width == info->minimum.width)
9071     return;
9072
9073   g_object_freeze_notify (G_OBJECT (self));
9074
9075   clutter_actor_store_old_geometry (self, &old);
9076
9077   info->minimum.width = min_width;
9078   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9079   clutter_actor_set_min_width_set (self, TRUE);
9080
9081   clutter_actor_notify_if_geometry_changed (self, &old);
9082
9083   g_object_thaw_notify (G_OBJECT (self));
9084
9085   clutter_actor_queue_relayout (self);
9086 }
9087
9088 static void
9089 clutter_actor_set_min_height (ClutterActor *self,
9090                               gfloat        min_height)
9091
9092 {
9093   ClutterActorPrivate *priv = self->priv;
9094   ClutterActorBox old = { 0, };
9095   ClutterLayoutInfo *info;
9096
9097   /* if we are setting the size on a top-level actor and the
9098    * backend only supports static top-levels (e.g. framebuffers)
9099    * then we ignore the passed value and we override it with
9100    * the stage implementation's preferred size.
9101    */
9102   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9103       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9104     return;
9105
9106   info = _clutter_actor_get_layout_info (self);
9107
9108   if (priv->min_height_set && min_height == info->minimum.height)
9109     return;
9110
9111   g_object_freeze_notify (G_OBJECT (self));
9112
9113   clutter_actor_store_old_geometry (self, &old);
9114
9115   info->minimum.height = min_height;
9116   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9117   clutter_actor_set_min_height_set (self, TRUE);
9118
9119   clutter_actor_notify_if_geometry_changed (self, &old);
9120
9121   g_object_thaw_notify (G_OBJECT (self));
9122
9123   clutter_actor_queue_relayout (self);
9124 }
9125
9126 static void
9127 clutter_actor_set_natural_width (ClutterActor *self,
9128                                  gfloat        natural_width)
9129 {
9130   ClutterActorPrivate *priv = self->priv;
9131   ClutterActorBox old = { 0, };
9132   ClutterLayoutInfo *info;
9133
9134   /* if we are setting the size on a top-level actor and the
9135    * backend only supports static top-levels (e.g. framebuffers)
9136    * then we ignore the passed value and we override it with
9137    * the stage implementation's preferred size.
9138    */
9139   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9140       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9141     return;
9142
9143   info = _clutter_actor_get_layout_info (self);
9144
9145   if (priv->natural_width_set && natural_width == info->natural.width)
9146     return;
9147
9148   g_object_freeze_notify (G_OBJECT (self));
9149
9150   clutter_actor_store_old_geometry (self, &old);
9151
9152   info->natural.width = natural_width;
9153   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9154   clutter_actor_set_natural_width_set (self, TRUE);
9155
9156   clutter_actor_notify_if_geometry_changed (self, &old);
9157
9158   g_object_thaw_notify (G_OBJECT (self));
9159
9160   clutter_actor_queue_relayout (self);
9161 }
9162
9163 static void
9164 clutter_actor_set_natural_height (ClutterActor *self,
9165                                   gfloat        natural_height)
9166 {
9167   ClutterActorPrivate *priv = self->priv;
9168   ClutterActorBox old = { 0, };
9169   ClutterLayoutInfo *info;
9170
9171   /* if we are setting the size on a top-level actor and the
9172    * backend only supports static top-levels (e.g. framebuffers)
9173    * then we ignore the passed value and we override it with
9174    * the stage implementation's preferred size.
9175    */
9176   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9177       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9178     return;
9179
9180   info = _clutter_actor_get_layout_info (self);
9181
9182   if (priv->natural_height_set && natural_height == info->natural.height)
9183     return;
9184
9185   g_object_freeze_notify (G_OBJECT (self));
9186
9187   clutter_actor_store_old_geometry (self, &old);
9188
9189   info->natural.height = natural_height;
9190   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9191   clutter_actor_set_natural_height_set (self, TRUE);
9192
9193   clutter_actor_notify_if_geometry_changed (self, &old);
9194
9195   g_object_thaw_notify (G_OBJECT (self));
9196
9197   clutter_actor_queue_relayout (self);
9198 }
9199
9200 static void
9201 clutter_actor_set_min_width_set (ClutterActor *self,
9202                                  gboolean      use_min_width)
9203 {
9204   ClutterActorPrivate *priv = self->priv;
9205   ClutterActorBox old = { 0, };
9206
9207   if (priv->min_width_set == (use_min_width != FALSE))
9208     return;
9209
9210   clutter_actor_store_old_geometry (self, &old);
9211
9212   priv->min_width_set = use_min_width != FALSE;
9213   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9214
9215   clutter_actor_notify_if_geometry_changed (self, &old);
9216
9217   clutter_actor_queue_relayout (self);
9218 }
9219
9220 static void
9221 clutter_actor_set_min_height_set (ClutterActor *self,
9222                                   gboolean      use_min_height)
9223 {
9224   ClutterActorPrivate *priv = self->priv;
9225   ClutterActorBox old = { 0, };
9226
9227   if (priv->min_height_set == (use_min_height != FALSE))
9228     return;
9229
9230   clutter_actor_store_old_geometry (self, &old);
9231
9232   priv->min_height_set = use_min_height != FALSE;
9233   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9234
9235   clutter_actor_notify_if_geometry_changed (self, &old);
9236
9237   clutter_actor_queue_relayout (self);
9238 }
9239
9240 static void
9241 clutter_actor_set_natural_width_set (ClutterActor *self,
9242                                      gboolean      use_natural_width)
9243 {
9244   ClutterActorPrivate *priv = self->priv;
9245   ClutterActorBox old = { 0, };
9246
9247   if (priv->natural_width_set == (use_natural_width != FALSE))
9248     return;
9249
9250   clutter_actor_store_old_geometry (self, &old);
9251
9252   priv->natural_width_set = use_natural_width != FALSE;
9253   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9254
9255   clutter_actor_notify_if_geometry_changed (self, &old);
9256
9257   clutter_actor_queue_relayout (self);
9258 }
9259
9260 static void
9261 clutter_actor_set_natural_height_set (ClutterActor *self,
9262                                       gboolean      use_natural_height)
9263 {
9264   ClutterActorPrivate *priv = self->priv;
9265   ClutterActorBox old = { 0, };
9266
9267   if (priv->natural_height_set == (use_natural_height != FALSE))
9268     return;
9269
9270   clutter_actor_store_old_geometry (self, &old);
9271
9272   priv->natural_height_set = use_natural_height != FALSE;
9273   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9274
9275   clutter_actor_notify_if_geometry_changed (self, &old);
9276
9277   clutter_actor_queue_relayout (self);
9278 }
9279
9280 /**
9281  * clutter_actor_set_request_mode:
9282  * @self: a #ClutterActor
9283  * @mode: the request mode
9284  *
9285  * Sets the geometry request mode of @self.
9286  *
9287  * The @mode determines the order for invoking
9288  * clutter_actor_get_preferred_width() and
9289  * clutter_actor_get_preferred_height()
9290  *
9291  * Since: 1.2
9292  */
9293 void
9294 clutter_actor_set_request_mode (ClutterActor       *self,
9295                                 ClutterRequestMode  mode)
9296 {
9297   ClutterActorPrivate *priv;
9298
9299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9300
9301   priv = self->priv;
9302
9303   if (priv->request_mode == mode)
9304     return;
9305
9306   priv->request_mode = mode;
9307
9308   priv->needs_width_request = TRUE;
9309   priv->needs_height_request = TRUE;
9310
9311   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9312
9313   clutter_actor_queue_relayout (self);
9314 }
9315
9316 /**
9317  * clutter_actor_get_request_mode:
9318  * @self: a #ClutterActor
9319  *
9320  * Retrieves the geometry request mode of @self
9321  *
9322  * Return value: the request mode for the actor
9323  *
9324  * Since: 1.2
9325  */
9326 ClutterRequestMode
9327 clutter_actor_get_request_mode (ClutterActor *self)
9328 {
9329   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9330                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9331
9332   return self->priv->request_mode;
9333 }
9334
9335 /* variant of set_width() without checks and without notification
9336  * freeze+thaw, for internal usage only
9337  */
9338 static inline void
9339 clutter_actor_set_width_internal (ClutterActor *self,
9340                                   gfloat        width)
9341 {
9342   if (width >= 0)
9343     {
9344       /* the Stage will use the :min-width to control the minimum
9345        * width to be resized to, so we should not be setting it
9346        * along with the :natural-width
9347        */
9348       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9349         clutter_actor_set_min_width (self, width);
9350
9351       clutter_actor_set_natural_width (self, width);
9352     }
9353   else
9354     {
9355       /* we only unset the :natural-width for the Stage */
9356       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9357         clutter_actor_set_min_width_set (self, FALSE);
9358
9359       clutter_actor_set_natural_width_set (self, FALSE);
9360     }
9361 }
9362
9363 /* variant of set_height() without checks and without notification
9364  * freeze+thaw, for internal usage only
9365  */
9366 static inline void
9367 clutter_actor_set_height_internal (ClutterActor *self,
9368                                    gfloat        height)
9369 {
9370   if (height >= 0)
9371     {
9372       /* see the comment above in set_width_internal() */
9373       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9374         clutter_actor_set_min_height (self, height);
9375
9376       clutter_actor_set_natural_height (self, height);
9377     }
9378   else
9379     {
9380       /* see the comment above in set_width_internal() */
9381       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9382         clutter_actor_set_min_height_set (self, FALSE);
9383
9384       clutter_actor_set_natural_height_set (self, FALSE);
9385     }
9386 }
9387
9388 static void
9389 clutter_actor_set_size_internal (ClutterActor      *self,
9390                                  const ClutterSize *size)
9391 {
9392   if (size != NULL)
9393     {
9394       clutter_actor_set_width_internal (self, size->width);
9395       clutter_actor_set_height_internal (self, size->height);
9396     }
9397   else
9398     {
9399       clutter_actor_set_width_internal (self, -1);
9400       clutter_actor_set_height_internal (self, -1);
9401     }
9402 }
9403
9404 /**
9405  * clutter_actor_set_size:
9406  * @self: A #ClutterActor
9407  * @width: New width of actor in pixels, or -1
9408  * @height: New height of actor in pixels, or -1
9409  *
9410  * Sets the actor's size request in pixels. This overrides any
9411  * "normal" size request the actor would have. For example
9412  * a text actor might normally request the size of the text;
9413  * this function would force a specific size instead.
9414  *
9415  * If @width and/or @height are -1 the actor will use its
9416  * "normal" size request instead of overriding it, i.e.
9417  * you can "unset" the size with -1.
9418  *
9419  * This function sets or unsets both the minimum and natural size.
9420  */
9421 void
9422 clutter_actor_set_size (ClutterActor *self,
9423                         gfloat        width,
9424                         gfloat        height)
9425 {
9426   ClutterSize new_size;
9427
9428   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9429
9430   clutter_size_init (&new_size, width, height);
9431
9432   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9433     {
9434       /* minor optimization: if we don't have a duration then we can
9435        * skip the get_size() below, to avoid the chance of going through
9436        * get_preferred_width() and get_preferred_height() just to jump to
9437        * a new desired size
9438        */
9439       if (clutter_actor_get_easing_duration (self) == 0)
9440         {
9441           g_object_freeze_notify (G_OBJECT (self));
9442
9443           clutter_actor_set_size_internal (self, &new_size);
9444
9445           g_object_thaw_notify (G_OBJECT (self));
9446
9447           return;
9448         }
9449       else
9450         {
9451           ClutterSize cur_size;
9452
9453           clutter_size_init (&cur_size,
9454                              clutter_actor_get_width (self),
9455                              clutter_actor_get_height (self));
9456
9457          _clutter_actor_create_transition (self,
9458                                            obj_props[PROP_SIZE],
9459                                            &cur_size,
9460                                            &new_size);
9461         }
9462     }
9463   else
9464     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9465
9466   clutter_actor_queue_relayout (self);
9467 }
9468
9469 /**
9470  * clutter_actor_get_size:
9471  * @self: A #ClutterActor
9472  * @width: (out) (allow-none): return location for the width, or %NULL.
9473  * @height: (out) (allow-none): return location for the height, or %NULL.
9474  *
9475  * This function tries to "do what you mean" and return
9476  * the size an actor will have. If the actor has a valid
9477  * allocation, the allocation will be returned; otherwise,
9478  * the actors natural size request will be returned.
9479  *
9480  * If you care whether you get the request vs. the allocation, you
9481  * should probably call a different function like
9482  * clutter_actor_get_allocation_box() or
9483  * clutter_actor_get_preferred_width().
9484  *
9485  * Since: 0.2
9486  */
9487 void
9488 clutter_actor_get_size (ClutterActor *self,
9489                         gfloat       *width,
9490                         gfloat       *height)
9491 {
9492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9493
9494   if (width)
9495     *width = clutter_actor_get_width (self);
9496
9497   if (height)
9498     *height = clutter_actor_get_height (self);
9499 }
9500
9501 /**
9502  * clutter_actor_get_position:
9503  * @self: a #ClutterActor
9504  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9505  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9506  *
9507  * This function tries to "do what you mean" and tell you where the
9508  * actor is, prior to any transformations. Retrieves the fixed
9509  * position of an actor in pixels, if one has been set; otherwise, if
9510  * the allocation is valid, returns the actor's allocated position;
9511  * otherwise, returns 0,0.
9512  *
9513  * The returned position is in pixels.
9514  *
9515  * Since: 0.6
9516  */
9517 void
9518 clutter_actor_get_position (ClutterActor *self,
9519                             gfloat       *x,
9520                             gfloat       *y)
9521 {
9522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9523
9524   if (x)
9525     *x = clutter_actor_get_x (self);
9526
9527   if (y)
9528     *y = clutter_actor_get_y (self);
9529 }
9530
9531 /**
9532  * clutter_actor_get_transformed_position:
9533  * @self: A #ClutterActor
9534  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9535  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9536  *
9537  * Gets the absolute position of an actor, in pixels relative to the stage.
9538  *
9539  * Since: 0.8
9540  */
9541 void
9542 clutter_actor_get_transformed_position (ClutterActor *self,
9543                                         gfloat       *x,
9544                                         gfloat       *y)
9545 {
9546   ClutterVertex v1;
9547   ClutterVertex v2;
9548
9549   v1.x = v1.y = v1.z = 0;
9550   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9551
9552   if (x)
9553     *x = v2.x;
9554
9555   if (y)
9556     *y = v2.y;
9557 }
9558
9559 /**
9560  * clutter_actor_get_transformed_size:
9561  * @self: A #ClutterActor
9562  * @width: (out) (allow-none): return location for the width, or %NULL
9563  * @height: (out) (allow-none): return location for the height, or %NULL
9564  *
9565  * Gets the absolute size of an actor in pixels, taking into account the
9566  * scaling factors.
9567  *
9568  * If the actor has a valid allocation, the allocated size will be used.
9569  * If the actor has not a valid allocation then the preferred size will
9570  * be transformed and returned.
9571  *
9572  * If you want the transformed allocation, see
9573  * clutter_actor_get_abs_allocation_vertices() instead.
9574  *
9575  * <note>When the actor (or one of its ancestors) is rotated around the
9576  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9577  * as a generic quadrangle; in that case this function returns the size
9578  * of the smallest rectangle that encapsulates the entire quad. Please
9579  * note that in this case no assumptions can be made about the relative
9580  * position of this envelope to the absolute position of the actor, as
9581  * returned by clutter_actor_get_transformed_position(); if you need this
9582  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9583  * to get the coords of the actual quadrangle.</note>
9584  *
9585  * Since: 0.8
9586  */
9587 void
9588 clutter_actor_get_transformed_size (ClutterActor *self,
9589                                     gfloat       *width,
9590                                     gfloat       *height)
9591 {
9592   ClutterActorPrivate *priv;
9593   ClutterVertex v[4];
9594   gfloat x_min, x_max, y_min, y_max;
9595   gint i;
9596
9597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9598
9599   priv = self->priv;
9600
9601   /* if the actor hasn't been allocated yet, get the preferred
9602    * size and transform that
9603    */
9604   if (priv->needs_allocation)
9605     {
9606       gfloat natural_width, natural_height;
9607       ClutterActorBox box;
9608
9609       /* Make a fake allocation to transform.
9610        *
9611        * NB: _clutter_actor_transform_and_project_box expects a box in
9612        * the actor's coordinate space... */
9613
9614       box.x1 = 0;
9615       box.y1 = 0;
9616
9617       natural_width = natural_height = 0;
9618       clutter_actor_get_preferred_size (self, NULL, NULL,
9619                                         &natural_width,
9620                                         &natural_height);
9621
9622       box.x2 = natural_width;
9623       box.y2 = natural_height;
9624
9625       _clutter_actor_transform_and_project_box (self, &box, v);
9626     }
9627   else
9628     clutter_actor_get_abs_allocation_vertices (self, v);
9629
9630   x_min = x_max = v[0].x;
9631   y_min = y_max = v[0].y;
9632
9633   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9634     {
9635       if (v[i].x < x_min)
9636         x_min = v[i].x;
9637
9638       if (v[i].x > x_max)
9639         x_max = v[i].x;
9640
9641       if (v[i].y < y_min)
9642         y_min = v[i].y;
9643
9644       if (v[i].y > y_max)
9645         y_max = v[i].y;
9646     }
9647
9648   if (width)
9649     *width  = x_max - x_min;
9650
9651   if (height)
9652     *height = y_max - y_min;
9653 }
9654
9655 /**
9656  * clutter_actor_get_width:
9657  * @self: A #ClutterActor
9658  *
9659  * Retrieves the width of a #ClutterActor.
9660  *
9661  * If the actor has a valid allocation, this function will return the
9662  * width of the allocated area given to the actor.
9663  *
9664  * If the actor does not have a valid allocation, this function will
9665  * return the actor's natural width, that is the preferred width of
9666  * the actor.
9667  *
9668  * If you care whether you get the preferred width or the width that
9669  * has been assigned to the actor, you should probably call a different
9670  * function like clutter_actor_get_allocation_box() to retrieve the
9671  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9672  * preferred width.
9673  *
9674  * If an actor has a fixed width, for instance a width that has been
9675  * assigned using clutter_actor_set_width(), the width returned will
9676  * be the same value.
9677  *
9678  * Return value: the width of the actor, in pixels
9679  */
9680 gfloat
9681 clutter_actor_get_width (ClutterActor *self)
9682 {
9683   ClutterActorPrivate *priv;
9684
9685   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9686
9687   priv = self->priv;
9688
9689   if (priv->needs_allocation)
9690     {
9691       gfloat natural_width = 0;
9692
9693       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9694         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9695       else
9696         {
9697           gfloat natural_height = 0;
9698
9699           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9700           clutter_actor_get_preferred_width (self, natural_height,
9701                                              NULL,
9702                                              &natural_width);
9703         }
9704
9705       return natural_width;
9706     }
9707   else
9708     return priv->allocation.x2 - priv->allocation.x1;
9709 }
9710
9711 /**
9712  * clutter_actor_get_height:
9713  * @self: A #ClutterActor
9714  *
9715  * Retrieves the height of a #ClutterActor.
9716  *
9717  * If the actor has a valid allocation, this function will return the
9718  * height of the allocated area given to the actor.
9719  *
9720  * If the actor does not have a valid allocation, this function will
9721  * return the actor's natural height, that is the preferred height of
9722  * the actor.
9723  *
9724  * If you care whether you get the preferred height or the height that
9725  * has been assigned to the actor, you should probably call a different
9726  * function like clutter_actor_get_allocation_box() to retrieve the
9727  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9728  * preferred height.
9729  *
9730  * If an actor has a fixed height, for instance a height that has been
9731  * assigned using clutter_actor_set_height(), the height returned will
9732  * be the same value.
9733  *
9734  * Return value: the height of the actor, in pixels
9735  */
9736 gfloat
9737 clutter_actor_get_height (ClutterActor *self)
9738 {
9739   ClutterActorPrivate *priv;
9740
9741   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9742
9743   priv = self->priv;
9744
9745   if (priv->needs_allocation)
9746     {
9747       gfloat natural_height = 0;
9748
9749       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9750         {
9751           gfloat natural_width = 0;
9752
9753           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9754           clutter_actor_get_preferred_height (self, natural_width,
9755                                               NULL, &natural_height);
9756         }
9757       else
9758         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9759
9760       return natural_height;
9761     }
9762   else
9763     return priv->allocation.y2 - priv->allocation.y1;
9764 }
9765
9766 /**
9767  * clutter_actor_set_width:
9768  * @self: A #ClutterActor
9769  * @width: Requested new width for the actor, in pixels, or -1
9770  *
9771  * Forces a width on an actor, causing the actor's preferred width
9772  * and height (if any) to be ignored.
9773  *
9774  * If @width is -1 the actor will use its preferred width request
9775  * instead of overriding it, i.e. you can "unset" the width with -1.
9776  *
9777  * This function sets both the minimum and natural size of the actor.
9778  *
9779  * since: 0.2
9780  */
9781 void
9782 clutter_actor_set_width (ClutterActor *self,
9783                          gfloat        width)
9784 {
9785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9786
9787   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9788     {
9789       float cur_size;
9790
9791       /* minor optimization: if we don't have a duration
9792        * then we can skip the get_width() below, to avoid
9793        * the chance of going through get_preferred_width()
9794        * just to jump to a new desired width.
9795        */
9796       if (clutter_actor_get_easing_duration (self) == 0)
9797         {
9798           g_object_freeze_notify (G_OBJECT (self));
9799
9800           clutter_actor_set_width_internal (self, width);
9801
9802           g_object_thaw_notify (G_OBJECT (self));
9803
9804           return;
9805         }
9806       else
9807         cur_size = clutter_actor_get_width (self);
9808
9809       _clutter_actor_create_transition (self,
9810                                         obj_props[PROP_WIDTH],
9811                                         cur_size,
9812                                         width);
9813     }
9814   else
9815     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9816 }
9817
9818 /**
9819  * clutter_actor_set_height:
9820  * @self: A #ClutterActor
9821  * @height: Requested new height for the actor, in pixels, or -1
9822  *
9823  * Forces a height on an actor, causing the actor's preferred width
9824  * and height (if any) to be ignored.
9825  *
9826  * If @height is -1 the actor will use its preferred height instead of
9827  * overriding it, i.e. you can "unset" the height with -1.
9828  *
9829  * This function sets both the minimum and natural size of the actor.
9830  *
9831  * since: 0.2
9832  */
9833 void
9834 clutter_actor_set_height (ClutterActor *self,
9835                           gfloat        height)
9836 {
9837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9838
9839   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9840     {
9841       float cur_size;
9842
9843       /* see the comment in clutter_actor_set_width() above */
9844       if (clutter_actor_get_easing_duration (self) == 0)
9845         {
9846           g_object_freeze_notify (G_OBJECT (self));
9847
9848           clutter_actor_set_height_internal (self, height);
9849
9850           g_object_thaw_notify (G_OBJECT (self));
9851
9852           return;
9853         }
9854       else
9855         cur_size = clutter_actor_get_height (self);
9856
9857       _clutter_actor_create_transition (self,
9858                                         obj_props[PROP_HEIGHT],
9859                                         cur_size,
9860                                         height);
9861     }
9862   else
9863     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9864 }
9865
9866 static inline void
9867 clutter_actor_set_x_internal (ClutterActor *self,
9868                               float         x)
9869 {
9870   ClutterActorPrivate *priv = self->priv;
9871   ClutterLayoutInfo *linfo;
9872   ClutterActorBox old = { 0, };
9873
9874   linfo = _clutter_actor_get_layout_info (self);
9875
9876   if (priv->position_set && linfo->fixed_pos.x == x)
9877     return;
9878
9879   clutter_actor_store_old_geometry (self, &old);
9880
9881   linfo->fixed_pos.x = x;
9882   clutter_actor_set_fixed_position_set (self, TRUE);
9883
9884   clutter_actor_notify_if_geometry_changed (self, &old);
9885
9886   clutter_actor_queue_relayout (self);
9887 }
9888
9889 static inline void
9890 clutter_actor_set_y_internal (ClutterActor *self,
9891                               float         y)
9892 {
9893   ClutterActorPrivate *priv = self->priv;
9894   ClutterLayoutInfo *linfo;
9895   ClutterActorBox old = { 0, };
9896
9897   linfo = _clutter_actor_get_layout_info (self);
9898
9899   if (priv->position_set && linfo->fixed_pos.y == y)
9900     return;
9901
9902   clutter_actor_store_old_geometry (self, &old);
9903
9904   linfo->fixed_pos.y = y;
9905   clutter_actor_set_fixed_position_set (self, TRUE);
9906
9907   clutter_actor_notify_if_geometry_changed (self, &old);
9908
9909   clutter_actor_queue_relayout (self);
9910 }
9911
9912 static void
9913 clutter_actor_set_position_internal (ClutterActor       *self,
9914                                      const ClutterPoint *position)
9915 {
9916   ClutterActorPrivate *priv = self->priv;
9917   ClutterLayoutInfo *linfo;
9918   ClutterActorBox old = { 0, };
9919
9920   linfo = _clutter_actor_get_layout_info (self);
9921
9922   if (priv->position_set &&
9923       clutter_point_equals (position, &linfo->fixed_pos))
9924     return;
9925
9926   clutter_actor_store_old_geometry (self, &old);
9927
9928   if (position != NULL)
9929     {
9930       linfo->fixed_pos = *position;
9931       clutter_actor_set_fixed_position_set (self, TRUE);
9932     }
9933   else
9934     clutter_actor_set_fixed_position_set (self, FALSE);
9935
9936   clutter_actor_notify_if_geometry_changed (self, &old);
9937
9938   clutter_actor_queue_relayout (self);
9939 }
9940
9941 /**
9942  * clutter_actor_set_x:
9943  * @self: a #ClutterActor
9944  * @x: the actor's position on the X axis
9945  *
9946  * Sets the actor's X coordinate, relative to its parent, in pixels.
9947  *
9948  * Overrides any layout manager and forces a fixed position for
9949  * the actor.
9950  *
9951  * The #ClutterActor:x property is animatable.
9952  *
9953  * Since: 0.6
9954  */
9955 void
9956 clutter_actor_set_x (ClutterActor *self,
9957                      gfloat        x)
9958 {
9959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9960
9961   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9962     {
9963       float cur_position = clutter_actor_get_x (self);
9964
9965       _clutter_actor_create_transition (self, obj_props[PROP_X],
9966                                         cur_position,
9967                                         x);
9968     }
9969   else
9970     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9971 }
9972
9973 /**
9974  * clutter_actor_set_y:
9975  * @self: a #ClutterActor
9976  * @y: the actor's position on the Y axis
9977  *
9978  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9979  *
9980  * Overrides any layout manager and forces a fixed position for
9981  * the actor.
9982  *
9983  * The #ClutterActor:y property is animatable.
9984  *
9985  * Since: 0.6
9986  */
9987 void
9988 clutter_actor_set_y (ClutterActor *self,
9989                      gfloat        y)
9990 {
9991   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9992
9993   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9994     {
9995       float cur_position = clutter_actor_get_y (self);
9996
9997       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9998                                         cur_position,
9999                                         y);
10000     }
10001   else
10002     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10003 }
10004
10005 /**
10006  * clutter_actor_get_x:
10007  * @self: A #ClutterActor
10008  *
10009  * Retrieves the X coordinate of a #ClutterActor.
10010  *
10011  * This function tries to "do what you mean", by returning the
10012  * correct value depending on the actor's state.
10013  *
10014  * If the actor has a valid allocation, this function will return
10015  * the X coordinate of the origin of the allocation box.
10016  *
10017  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10018  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10019  * function will return that coordinate.
10020  *
10021  * If both the allocation and a fixed position are missing, this function
10022  * will return 0.
10023  *
10024  * Return value: the X coordinate, in pixels, ignoring any
10025  *   transformation (i.e. scaling, rotation)
10026  */
10027 gfloat
10028 clutter_actor_get_x (ClutterActor *self)
10029 {
10030   ClutterActorPrivate *priv;
10031
10032   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10033
10034   priv = self->priv;
10035
10036   if (priv->needs_allocation)
10037     {
10038       if (priv->position_set)
10039         {
10040           const ClutterLayoutInfo *info;
10041
10042           info = _clutter_actor_get_layout_info_or_defaults (self);
10043
10044           return info->fixed_pos.x;
10045         }
10046       else
10047         return 0;
10048     }
10049   else
10050     return priv->allocation.x1;
10051 }
10052
10053 /**
10054  * clutter_actor_get_y:
10055  * @self: A #ClutterActor
10056  *
10057  * Retrieves the Y coordinate of a #ClutterActor.
10058  *
10059  * This function tries to "do what you mean", by returning the
10060  * correct value depending on the actor's state.
10061  *
10062  * If the actor has a valid allocation, this function will return
10063  * the Y coordinate of the origin of the allocation box.
10064  *
10065  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10066  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10067  * function will return that coordinate.
10068  *
10069  * If both the allocation and a fixed position are missing, this function
10070  * will return 0.
10071  *
10072  * Return value: the Y coordinate, in pixels, ignoring any
10073  *   transformation (i.e. scaling, rotation)
10074  */
10075 gfloat
10076 clutter_actor_get_y (ClutterActor *self)
10077 {
10078   ClutterActorPrivate *priv;
10079
10080   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10081
10082   priv = self->priv;
10083
10084   if (priv->needs_allocation)
10085     {
10086       if (priv->position_set)
10087         {
10088           const ClutterLayoutInfo *info;
10089
10090           info = _clutter_actor_get_layout_info_or_defaults (self);
10091
10092           return info->fixed_pos.y;
10093         }
10094       else
10095         return 0;
10096     }
10097   else
10098     return priv->allocation.y1;
10099 }
10100
10101 /**
10102  * clutter_actor_set_scale:
10103  * @self: A #ClutterActor
10104  * @scale_x: double factor to scale actor by horizontally.
10105  * @scale_y: double factor to scale actor by vertically.
10106  *
10107  * Scales an actor with the given factors. The scaling is relative to
10108  * the scale center and the anchor point. The scale center is
10109  * unchanged by this function and defaults to 0,0.
10110  *
10111  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10112  * animatable.
10113  *
10114  * Since: 0.2
10115  */
10116 void
10117 clutter_actor_set_scale (ClutterActor *self,
10118                          gdouble       scale_x,
10119                          gdouble       scale_y)
10120 {
10121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10122
10123   g_object_freeze_notify (G_OBJECT (self));
10124
10125   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10126   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10127
10128   g_object_thaw_notify (G_OBJECT (self));
10129 }
10130
10131 /**
10132  * clutter_actor_set_scale_full:
10133  * @self: A #ClutterActor
10134  * @scale_x: double factor to scale actor by horizontally.
10135  * @scale_y: double factor to scale actor by vertically.
10136  * @center_x: X coordinate of the center of the scale.
10137  * @center_y: Y coordinate of the center of the scale
10138  *
10139  * Scales an actor with the given factors around the given center
10140  * point. The center point is specified in pixels relative to the
10141  * anchor point (usually the top left corner of the actor).
10142  *
10143  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10144  * are animatable.
10145  *
10146  * Since: 1.0
10147  */
10148 void
10149 clutter_actor_set_scale_full (ClutterActor *self,
10150                               gdouble       scale_x,
10151                               gdouble       scale_y,
10152                               gfloat        center_x,
10153                               gfloat        center_y)
10154 {
10155   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10156
10157   g_object_freeze_notify (G_OBJECT (self));
10158
10159   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10160   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10161   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10162   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10163
10164   g_object_thaw_notify (G_OBJECT (self));
10165 }
10166
10167 /**
10168  * clutter_actor_set_scale_with_gravity:
10169  * @self: A #ClutterActor
10170  * @scale_x: double factor to scale actor by horizontally.
10171  * @scale_y: double factor to scale actor by vertically.
10172  * @gravity: the location of the scale center expressed as a compass
10173  * direction.
10174  *
10175  * Scales an actor with the given factors around the given
10176  * center point. The center point is specified as one of the compass
10177  * directions in #ClutterGravity. For example, setting it to north
10178  * will cause the top of the actor to remain unchanged and the rest of
10179  * the actor to expand left, right and downwards.
10180  *
10181  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10182  * animatable.
10183  *
10184  * Since: 1.0
10185  */
10186 void
10187 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10188                                       gdouble         scale_x,
10189                                       gdouble         scale_y,
10190                                       ClutterGravity  gravity)
10191 {
10192   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10193
10194   g_object_freeze_notify (G_OBJECT (self));
10195
10196   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10197   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10198   clutter_actor_set_scale_gravity (self, gravity);
10199
10200   g_object_thaw_notify (G_OBJECT (self));
10201 }
10202
10203 /**
10204  * clutter_actor_get_scale:
10205  * @self: A #ClutterActor
10206  * @scale_x: (out) (allow-none): Location to store horizonal
10207  *   scale factor, or %NULL.
10208  * @scale_y: (out) (allow-none): Location to store vertical
10209  *   scale factor, or %NULL.
10210  *
10211  * Retrieves an actors scale factors.
10212  *
10213  * Since: 0.2
10214  */
10215 void
10216 clutter_actor_get_scale (ClutterActor *self,
10217                          gdouble      *scale_x,
10218                          gdouble      *scale_y)
10219 {
10220   const ClutterTransformInfo *info;
10221
10222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10223
10224   info = _clutter_actor_get_transform_info_or_defaults (self);
10225
10226   if (scale_x)
10227     *scale_x = info->scale_x;
10228
10229   if (scale_y)
10230     *scale_y = info->scale_y;
10231 }
10232
10233 /**
10234  * clutter_actor_get_scale_center:
10235  * @self: A #ClutterActor
10236  * @center_x: (out) (allow-none): Location to store the X position
10237  *   of the scale center, or %NULL.
10238  * @center_y: (out) (allow-none): Location to store the Y position
10239  *   of the scale center, or %NULL.
10240  *
10241  * Retrieves the scale center coordinate in pixels relative to the top
10242  * left corner of the actor. If the scale center was specified using a
10243  * #ClutterGravity this will calculate the pixel offset using the
10244  * current size of the actor.
10245  *
10246  * Since: 1.0
10247  */
10248 void
10249 clutter_actor_get_scale_center (ClutterActor *self,
10250                                 gfloat       *center_x,
10251                                 gfloat       *center_y)
10252 {
10253   const ClutterTransformInfo *info;
10254
10255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10256
10257   info = _clutter_actor_get_transform_info_or_defaults (self);
10258
10259   clutter_anchor_coord_get_units (self, &info->scale_center,
10260                                   center_x,
10261                                   center_y,
10262                                   NULL);
10263 }
10264
10265 /**
10266  * clutter_actor_get_scale_gravity:
10267  * @self: A #ClutterActor
10268  *
10269  * Retrieves the scale center as a compass direction. If the scale
10270  * center was specified in pixels or units this will return
10271  * %CLUTTER_GRAVITY_NONE.
10272  *
10273  * Return value: the scale gravity
10274  *
10275  * Since: 1.0
10276  */
10277 ClutterGravity
10278 clutter_actor_get_scale_gravity (ClutterActor *self)
10279 {
10280   const ClutterTransformInfo *info;
10281
10282   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10283
10284   info = _clutter_actor_get_transform_info_or_defaults (self);
10285
10286   return clutter_anchor_coord_get_gravity (&info->scale_center);
10287 }
10288
10289 static inline void
10290 clutter_actor_set_opacity_internal (ClutterActor *self,
10291                                     guint8        opacity)
10292 {
10293   ClutterActorPrivate *priv = self->priv;
10294
10295   if (priv->opacity != opacity)
10296     {
10297       priv->opacity = opacity;
10298
10299       /* Queue a redraw from the flatten effect so that it can use
10300          its cached image if available instead of having to redraw the
10301          actual actor. If it doesn't end up using the FBO then the
10302          effect is still able to continue the paint anyway. If there
10303          is no flatten effect yet then this is equivalent to queueing
10304          a full redraw */
10305       _clutter_actor_queue_redraw_full (self,
10306                                         0, /* flags */
10307                                         NULL, /* clip */
10308                                         priv->flatten_effect);
10309
10310       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10311     }
10312 }
10313
10314 /**
10315  * clutter_actor_set_opacity:
10316  * @self: A #ClutterActor
10317  * @opacity: New opacity value for the actor.
10318  *
10319  * Sets the actor's opacity, with zero being completely transparent and
10320  * 255 (0xff) being fully opaque.
10321  *
10322  * The #ClutterActor:opacity property is animatable.
10323  */
10324 void
10325 clutter_actor_set_opacity (ClutterActor *self,
10326                            guint8        opacity)
10327 {
10328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10329
10330   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10331     {
10332       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10333                                         self->priv->opacity,
10334                                         opacity);
10335     }
10336   else
10337     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10338 }
10339
10340 /*
10341  * clutter_actor_get_paint_opacity_internal:
10342  * @self: a #ClutterActor
10343  *
10344  * Retrieves the absolute opacity of the actor, as it appears on the stage
10345  *
10346  * This function does not do type checks
10347  *
10348  * Return value: the absolute opacity of the actor
10349  */
10350 static guint8
10351 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10352 {
10353   ClutterActorPrivate *priv = self->priv;
10354   ClutterActor *parent;
10355
10356   /* override the top-level opacity to always be 255; even in
10357    * case of ClutterStage:use-alpha being TRUE we want the rest
10358    * of the scene to be painted
10359    */
10360   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10361     return 255;
10362
10363   if (priv->opacity_override >= 0)
10364     return priv->opacity_override;
10365
10366   parent = priv->parent;
10367
10368   /* Factor in the actual actors opacity with parents */
10369   if (parent != NULL)
10370     {
10371       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10372
10373       if (opacity != 0xff)
10374         return (opacity * priv->opacity) / 0xff;
10375     }
10376
10377   return priv->opacity;
10378
10379 }
10380
10381 /**
10382  * clutter_actor_get_paint_opacity:
10383  * @self: A #ClutterActor
10384  *
10385  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10386  *
10387  * This function traverses the hierarchy chain and composites the opacity of
10388  * the actor with that of its parents.
10389  *
10390  * This function is intended for subclasses to use in the paint virtual
10391  * function, to paint themselves with the correct opacity.
10392  *
10393  * Return value: The actor opacity value.
10394  *
10395  * Since: 0.8
10396  */
10397 guint8
10398 clutter_actor_get_paint_opacity (ClutterActor *self)
10399 {
10400   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10401
10402   return clutter_actor_get_paint_opacity_internal (self);
10403 }
10404
10405 /**
10406  * clutter_actor_get_opacity:
10407  * @self: a #ClutterActor
10408  *
10409  * Retrieves the opacity value of an actor, as set by
10410  * clutter_actor_set_opacity().
10411  *
10412  * For retrieving the absolute opacity of the actor inside a paint
10413  * virtual function, see clutter_actor_get_paint_opacity().
10414  *
10415  * Return value: the opacity of the actor
10416  */
10417 guint8
10418 clutter_actor_get_opacity (ClutterActor *self)
10419 {
10420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10421
10422   return self->priv->opacity;
10423 }
10424
10425 /**
10426  * clutter_actor_set_offscreen_redirect:
10427  * @self: A #ClutterActor
10428  * @redirect: New offscreen redirect flags for the actor.
10429  *
10430  * Defines the circumstances where the actor should be redirected into
10431  * an offscreen image. The offscreen image is used to flatten the
10432  * actor into a single image while painting for two main reasons.
10433  * Firstly, when the actor is painted a second time without any of its
10434  * contents changing it can simply repaint the cached image without
10435  * descending further down the actor hierarchy. Secondly, it will make
10436  * the opacity look correct even if there are overlapping primitives
10437  * in the actor.
10438  *
10439  * Caching the actor could in some cases be a performance win and in
10440  * some cases be a performance lose so it is important to determine
10441  * which value is right for an actor before modifying this value. For
10442  * example, there is never any reason to flatten an actor that is just
10443  * a single texture (such as a #ClutterTexture) because it is
10444  * effectively already cached in an image so the offscreen would be
10445  * redundant. Also if the actor contains primitives that are far apart
10446  * with a large transparent area in the middle (such as a large
10447  * CluterGroup with a small actor in the top left and a small actor in
10448  * the bottom right) then the cached image will contain the entire
10449  * image of the large area and the paint will waste time blending all
10450  * of the transparent pixels in the middle.
10451  *
10452  * The default method of implementing opacity on a container simply
10453  * forwards on the opacity to all of the children. If the children are
10454  * overlapping then it will appear as if they are two separate glassy
10455  * objects and there will be a break in the color where they
10456  * overlap. By redirecting to an offscreen buffer it will be as if the
10457  * two opaque objects are combined into one and then made transparent
10458  * which is usually what is expected.
10459  *
10460  * The image below demonstrates the difference between redirecting and
10461  * not. The image shows two Clutter groups, each containing a red and
10462  * a green rectangle which overlap. The opacity on the group is set to
10463  * 128 (which is 50%). When the offscreen redirect is not used, the
10464  * red rectangle can be seen through the blue rectangle as if the two
10465  * rectangles were separately transparent. When the redirect is used
10466  * the group as a whole is transparent instead so the red rectangle is
10467  * not visible where they overlap.
10468  *
10469  * <figure id="offscreen-redirect">
10470  *   <title>Sample of using an offscreen redirect for transparency</title>
10471  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10472  * </figure>
10473  *
10474  * The default value for this property is 0, so we effectively will
10475  * never redirect an actor offscreen by default. This means that there
10476  * are times that transparent actors may look glassy as described
10477  * above. The reason this is the default is because there is a
10478  * performance trade off between quality and performance here. In many
10479  * cases the default form of glassy opacity looks good enough, but if
10480  * it's not you will need to set the
10481  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10482  * redirection for opacity.
10483  *
10484  * Custom actors that don't contain any overlapping primitives are
10485  * recommended to override the has_overlaps() virtual to return %FALSE
10486  * for maximum efficiency.
10487  *
10488  * Since: 1.8
10489  */
10490 void
10491 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10492                                       ClutterOffscreenRedirect redirect)
10493 {
10494   ClutterActorPrivate *priv;
10495
10496   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10497
10498   priv = self->priv;
10499
10500   if (priv->offscreen_redirect != redirect)
10501     {
10502       priv->offscreen_redirect = redirect;
10503
10504       /* Queue a redraw from the effect so that it can use its cached
10505          image if available instead of having to redraw the actual
10506          actor. If it doesn't end up using the FBO then the effect is
10507          still able to continue the paint anyway. If there is no
10508          effect then this is equivalent to queuing a full redraw */
10509       _clutter_actor_queue_redraw_full (self,
10510                                         0, /* flags */
10511                                         NULL, /* clip */
10512                                         priv->flatten_effect);
10513
10514       g_object_notify_by_pspec (G_OBJECT (self),
10515                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10516     }
10517 }
10518
10519 /**
10520  * clutter_actor_get_offscreen_redirect:
10521  * @self: a #ClutterActor
10522  *
10523  * Retrieves whether to redirect the actor to an offscreen buffer, as
10524  * set by clutter_actor_set_offscreen_redirect().
10525  *
10526  * Return value: the value of the offscreen-redirect property of the actor
10527  *
10528  * Since: 1.8
10529  */
10530 ClutterOffscreenRedirect
10531 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10532 {
10533   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10534
10535   return self->priv->offscreen_redirect;
10536 }
10537
10538 /**
10539  * clutter_actor_set_name:
10540  * @self: A #ClutterActor
10541  * @name: Textual tag to apply to actor
10542  *
10543  * Sets the given name to @self. The name can be used to identify
10544  * a #ClutterActor.
10545  */
10546 void
10547 clutter_actor_set_name (ClutterActor *self,
10548                         const gchar  *name)
10549 {
10550   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10551
10552   g_free (self->priv->name);
10553   self->priv->name = g_strdup (name);
10554
10555   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10556 }
10557
10558 /**
10559  * clutter_actor_get_name:
10560  * @self: A #ClutterActor
10561  *
10562  * Retrieves the name of @self.
10563  *
10564  * Return value: the name of the actor, or %NULL. The returned string is
10565  *   owned by the actor and should not be modified or freed.
10566  */
10567 const gchar *
10568 clutter_actor_get_name (ClutterActor *self)
10569 {
10570   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10571
10572   return self->priv->name;
10573 }
10574
10575 /**
10576  * clutter_actor_get_gid:
10577  * @self: A #ClutterActor
10578  *
10579  * Retrieves the unique id for @self.
10580  *
10581  * Return value: Globally unique value for this object instance.
10582  *
10583  * Since: 0.6
10584  *
10585  * Deprecated: 1.8: The id is not used any longer.
10586  */
10587 guint32
10588 clutter_actor_get_gid (ClutterActor *self)
10589 {
10590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10591
10592   return self->priv->id;
10593 }
10594
10595 static inline void
10596 clutter_actor_set_depth_internal (ClutterActor *self,
10597                                   float         depth)
10598 {
10599   ClutterTransformInfo *info;
10600
10601   info = _clutter_actor_get_transform_info (self);
10602
10603   if (info->depth != depth)
10604     {
10605       /* Sets Z value - XXX 2.0: should we invert? */
10606       info->depth = depth;
10607
10608       self->priv->transform_valid = FALSE;
10609
10610       /* FIXME - remove this crap; sadly, there are still containers
10611        * in Clutter that depend on this utter brain damage
10612        */
10613       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10614
10615       clutter_actor_queue_redraw (self);
10616
10617       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10618     }
10619 }
10620
10621 /**
10622  * clutter_actor_set_depth:
10623  * @self: a #ClutterActor
10624  * @depth: Z co-ord
10625  *
10626  * Sets the Z coordinate of @self to @depth.
10627  *
10628  * The unit used by @depth is dependant on the perspective setup. See
10629  * also clutter_stage_set_perspective().
10630  */
10631 void
10632 clutter_actor_set_depth (ClutterActor *self,
10633                          gfloat        depth)
10634 {
10635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10636
10637   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10638     {
10639       const ClutterTransformInfo *info;
10640
10641       info = _clutter_actor_get_transform_info_or_defaults (self);
10642
10643       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10644                                         info->depth,
10645                                         depth);
10646     }
10647   else
10648     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10649
10650   clutter_actor_queue_redraw (self);
10651 }
10652
10653 /**
10654  * clutter_actor_get_depth:
10655  * @self: a #ClutterActor
10656  *
10657  * Retrieves the depth of @self.
10658  *
10659  * Return value: the depth of the actor
10660  */
10661 gfloat
10662 clutter_actor_get_depth (ClutterActor *self)
10663 {
10664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10665
10666   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10667 }
10668
10669 /**
10670  * clutter_actor_set_rotation:
10671  * @self: a #ClutterActor
10672  * @axis: the axis of rotation
10673  * @angle: the angle of rotation
10674  * @x: X coordinate of the rotation center
10675  * @y: Y coordinate of the rotation center
10676  * @z: Z coordinate of the rotation center
10677  *
10678  * Sets the rotation angle of @self around the given axis.
10679  *
10680  * The rotation center coordinates used depend on the value of @axis:
10681  * <itemizedlist>
10682  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10683  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10684  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10685  * </itemizedlist>
10686  *
10687  * The rotation coordinates are relative to the anchor point of the
10688  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10689  * point is set, the upper left corner is assumed as the origin.
10690  *
10691  * Since: 0.8
10692  */
10693 void
10694 clutter_actor_set_rotation (ClutterActor      *self,
10695                             ClutterRotateAxis  axis,
10696                             gdouble            angle,
10697                             gfloat             x,
10698                             gfloat             y,
10699                             gfloat             z)
10700 {
10701   ClutterVertex v;
10702
10703   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10704
10705   v.x = x;
10706   v.y = y;
10707   v.z = z;
10708
10709   g_object_freeze_notify (G_OBJECT (self));
10710
10711   clutter_actor_set_rotation_angle (self, axis, angle);
10712   clutter_actor_set_rotation_center_internal (self, axis, &v);
10713
10714   g_object_thaw_notify (G_OBJECT (self));
10715 }
10716
10717 /**
10718  * clutter_actor_set_z_rotation_from_gravity:
10719  * @self: a #ClutterActor
10720  * @angle: the angle of rotation
10721  * @gravity: the center point of the rotation
10722  *
10723  * Sets the rotation angle of @self around the Z axis using the center
10724  * point specified as a compass point. For example to rotate such that
10725  * the center of the actor remains static you can use
10726  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10727  * will move accordingly.
10728  *
10729  * Since: 1.0
10730  */
10731 void
10732 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10733                                            gdouble         angle,
10734                                            ClutterGravity  gravity)
10735 {
10736   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10737
10738   if (gravity == CLUTTER_GRAVITY_NONE)
10739     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10740   else
10741     {
10742       GObject *obj = G_OBJECT (self);
10743       ClutterTransformInfo *info;
10744
10745       info = _clutter_actor_get_transform_info (self);
10746
10747       g_object_freeze_notify (obj);
10748
10749       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10750
10751       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10752       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10753       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10754
10755       g_object_thaw_notify (obj);
10756     }
10757 }
10758
10759 /**
10760  * clutter_actor_get_rotation:
10761  * @self: a #ClutterActor
10762  * @axis: the axis of rotation
10763  * @x: (out): return value for the X coordinate of the center of rotation
10764  * @y: (out): return value for the Y coordinate of the center of rotation
10765  * @z: (out): return value for the Z coordinate of the center of rotation
10766  *
10767  * Retrieves the angle and center of rotation on the given axis,
10768  * set using clutter_actor_set_rotation().
10769  *
10770  * Return value: the angle of rotation
10771  *
10772  * Since: 0.8
10773  */
10774 gdouble
10775 clutter_actor_get_rotation (ClutterActor      *self,
10776                             ClutterRotateAxis  axis,
10777                             gfloat            *x,
10778                             gfloat            *y,
10779                             gfloat            *z)
10780 {
10781   const ClutterTransformInfo *info;
10782   const AnchorCoord *anchor_coord;
10783   gdouble retval = 0;
10784
10785   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10786
10787   info = _clutter_actor_get_transform_info_or_defaults (self);
10788
10789   switch (axis)
10790     {
10791     case CLUTTER_X_AXIS:
10792       anchor_coord = &info->rx_center;
10793       retval = info->rx_angle;
10794       break;
10795
10796     case CLUTTER_Y_AXIS:
10797       anchor_coord = &info->ry_center;
10798       retval = info->ry_angle;
10799       break;
10800
10801     case CLUTTER_Z_AXIS:
10802       anchor_coord = &info->rz_center;
10803       retval = info->rz_angle;
10804       break;
10805
10806     default:
10807       anchor_coord = NULL;
10808       retval = 0.0;
10809       break;
10810     }
10811
10812   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10813
10814   return retval;
10815 }
10816
10817 /**
10818  * clutter_actor_get_z_rotation_gravity:
10819  * @self: A #ClutterActor
10820  *
10821  * Retrieves the center for the rotation around the Z axis as a
10822  * compass direction. If the center was specified in pixels or units
10823  * this will return %CLUTTER_GRAVITY_NONE.
10824  *
10825  * Return value: the Z rotation center
10826  *
10827  * Since: 1.0
10828  */
10829 ClutterGravity
10830 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10831 {
10832   const ClutterTransformInfo *info;
10833
10834   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10835
10836   info = _clutter_actor_get_transform_info_or_defaults (self);
10837
10838   return clutter_anchor_coord_get_gravity (&info->rz_center);
10839 }
10840
10841 /**
10842  * clutter_actor_set_clip:
10843  * @self: A #ClutterActor
10844  * @xoff: X offset of the clip rectangle
10845  * @yoff: Y offset of the clip rectangle
10846  * @width: Width of the clip rectangle
10847  * @height: Height of the clip rectangle
10848  *
10849  * Sets clip area for @self. The clip area is always computed from the
10850  * upper left corner of the actor, even if the anchor point is set
10851  * otherwise.
10852  *
10853  * Since: 0.6
10854  */
10855 void
10856 clutter_actor_set_clip (ClutterActor *self,
10857                         gfloat        xoff,
10858                         gfloat        yoff,
10859                         gfloat        width,
10860                         gfloat        height)
10861 {
10862   ClutterActorPrivate *priv;
10863
10864   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10865
10866   priv = self->priv;
10867
10868   if (priv->has_clip &&
10869       priv->clip.x == xoff &&
10870       priv->clip.y == yoff &&
10871       priv->clip.width == width &&
10872       priv->clip.height == height)
10873     return;
10874
10875   priv->clip.x = xoff;
10876   priv->clip.y = yoff;
10877   priv->clip.width = width;
10878   priv->clip.height = height;
10879
10880   priv->has_clip = TRUE;
10881
10882   clutter_actor_queue_redraw (self);
10883
10884   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10885   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10886 }
10887
10888 /**
10889  * clutter_actor_remove_clip:
10890  * @self: A #ClutterActor
10891  *
10892  * Removes clip area from @self.
10893  */
10894 void
10895 clutter_actor_remove_clip (ClutterActor *self)
10896 {
10897   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10898
10899   if (!self->priv->has_clip)
10900     return;
10901
10902   self->priv->has_clip = FALSE;
10903
10904   clutter_actor_queue_redraw (self);
10905
10906   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10907 }
10908
10909 /**
10910  * clutter_actor_has_clip:
10911  * @self: a #ClutterActor
10912  *
10913  * Determines whether the actor has a clip area set or not.
10914  *
10915  * Return value: %TRUE if the actor has a clip area set.
10916  *
10917  * Since: 0.1.1
10918  */
10919 gboolean
10920 clutter_actor_has_clip (ClutterActor *self)
10921 {
10922   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10923
10924   return self->priv->has_clip;
10925 }
10926
10927 /**
10928  * clutter_actor_get_clip:
10929  * @self: a #ClutterActor
10930  * @xoff: (out) (allow-none): return location for the X offset of
10931  *   the clip rectangle, or %NULL
10932  * @yoff: (out) (allow-none): return location for the Y offset of
10933  *   the clip rectangle, or %NULL
10934  * @width: (out) (allow-none): return location for the width of
10935  *   the clip rectangle, or %NULL
10936  * @height: (out) (allow-none): return location for the height of
10937  *   the clip rectangle, or %NULL
10938  *
10939  * Gets the clip area for @self, if any is set
10940  *
10941  * Since: 0.6
10942  */
10943 void
10944 clutter_actor_get_clip (ClutterActor *self,
10945                         gfloat       *xoff,
10946                         gfloat       *yoff,
10947                         gfloat       *width,
10948                         gfloat       *height)
10949 {
10950   ClutterActorPrivate *priv;
10951
10952   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10953
10954   priv = self->priv;
10955
10956   if (!priv->has_clip)
10957     return;
10958
10959   if (xoff != NULL)
10960     *xoff = priv->clip.x;
10961
10962   if (yoff != NULL)
10963     *yoff = priv->clip.y;
10964
10965   if (width != NULL)
10966     *width = priv->clip.width;
10967
10968   if (height != NULL)
10969     *height = priv->clip.height;
10970 }
10971
10972 /**
10973  * clutter_actor_get_children:
10974  * @self: a #ClutterActor
10975  *
10976  * Retrieves the list of children of @self.
10977  *
10978  * Return value: (transfer container) (element-type ClutterActor): A newly
10979  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10980  *   done.
10981  *
10982  * Since: 1.10
10983  */
10984 GList *
10985 clutter_actor_get_children (ClutterActor *self)
10986 {
10987   ClutterActor *iter;
10988   GList *res;
10989
10990   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10991
10992   /* we walk the list backward so that we can use prepend(),
10993    * which is O(1)
10994    */
10995   for (iter = self->priv->last_child, res = NULL;
10996        iter != NULL;
10997        iter = iter->priv->prev_sibling)
10998     {
10999       res = g_list_prepend (res, iter);
11000     }
11001
11002   return res;
11003 }
11004
11005 /*< private >
11006  * insert_child_at_depth:
11007  * @self: a #ClutterActor
11008  * @child: a #ClutterActor
11009  *
11010  * Inserts @child inside the list of children held by @self, using
11011  * the depth as the insertion criteria.
11012  *
11013  * This sadly makes the insertion not O(1), but we can keep the
11014  * list sorted so that the painters algorithm we use for painting
11015  * the children will work correctly.
11016  */
11017 static void
11018 insert_child_at_depth (ClutterActor *self,
11019                        ClutterActor *child,
11020                        gpointer      dummy G_GNUC_UNUSED)
11021 {
11022   ClutterActor *iter;
11023   float child_depth;
11024
11025   child->priv->parent = self;
11026
11027   child_depth =
11028     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11029
11030   /* special-case the first child */
11031   if (self->priv->n_children == 0)
11032     {
11033       self->priv->first_child = child;
11034       self->priv->last_child = child;
11035
11036       child->priv->next_sibling = NULL;
11037       child->priv->prev_sibling = NULL;
11038
11039       return;
11040     }
11041
11042   /* Find the right place to insert the child so that it will still be
11043      sorted and the child will be after all of the actors at the same
11044      dept */
11045   for (iter = self->priv->first_child;
11046        iter != NULL;
11047        iter = iter->priv->next_sibling)
11048     {
11049       float iter_depth;
11050
11051       iter_depth =
11052         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11053
11054       if (iter_depth > child_depth)
11055         break;
11056     }
11057
11058   if (iter != NULL)
11059     {
11060       ClutterActor *tmp = iter->priv->prev_sibling;
11061
11062       if (tmp != NULL)
11063         tmp->priv->next_sibling = child;
11064
11065       /* Insert the node before the found one */
11066       child->priv->prev_sibling = iter->priv->prev_sibling;
11067       child->priv->next_sibling = iter;
11068       iter->priv->prev_sibling = child;
11069     }
11070   else
11071     {
11072       ClutterActor *tmp = self->priv->last_child;
11073
11074       if (tmp != NULL)
11075         tmp->priv->next_sibling = child;
11076
11077       /* insert the node at the end of the list */
11078       child->priv->prev_sibling = self->priv->last_child;
11079       child->priv->next_sibling = NULL;
11080     }
11081
11082   if (child->priv->prev_sibling == NULL)
11083     self->priv->first_child = child;
11084
11085   if (child->priv->next_sibling == NULL)
11086     self->priv->last_child = child;
11087 }
11088
11089 static void
11090 insert_child_at_index (ClutterActor *self,
11091                        ClutterActor *child,
11092                        gpointer      data_)
11093 {
11094   gint index_ = GPOINTER_TO_INT (data_);
11095
11096   child->priv->parent = self;
11097
11098   if (index_ == 0)
11099     {
11100       ClutterActor *tmp = self->priv->first_child;
11101
11102       if (tmp != NULL)
11103         tmp->priv->prev_sibling = child;
11104
11105       child->priv->prev_sibling = NULL;
11106       child->priv->next_sibling = tmp;
11107     }
11108   else if (index_ < 0 || index_ >= self->priv->n_children)
11109     {
11110       ClutterActor *tmp = self->priv->last_child;
11111
11112       if (tmp != NULL)
11113         tmp->priv->next_sibling = child;
11114
11115       child->priv->prev_sibling = tmp;
11116       child->priv->next_sibling = NULL;
11117     }
11118   else
11119     {
11120       ClutterActor *iter;
11121       int i;
11122
11123       for (iter = self->priv->first_child, i = 0;
11124            iter != NULL;
11125            iter = iter->priv->next_sibling, i += 1)
11126         {
11127           if (index_ == i)
11128             {
11129               ClutterActor *tmp = iter->priv->prev_sibling;
11130
11131               child->priv->prev_sibling = tmp;
11132               child->priv->next_sibling = iter;
11133
11134               iter->priv->prev_sibling = child;
11135
11136               if (tmp != NULL)
11137                 tmp->priv->next_sibling = child;
11138
11139               break;
11140             }
11141         }
11142     }
11143
11144   if (child->priv->prev_sibling == NULL)
11145     self->priv->first_child = child;
11146
11147   if (child->priv->next_sibling == NULL)
11148     self->priv->last_child = child;
11149 }
11150
11151 static void
11152 insert_child_above (ClutterActor *self,
11153                     ClutterActor *child,
11154                     gpointer      data)
11155 {
11156   ClutterActor *sibling = data;
11157
11158   child->priv->parent = self;
11159
11160   if (sibling == NULL)
11161     sibling = self->priv->last_child;
11162
11163   child->priv->prev_sibling = sibling;
11164
11165   if (sibling != NULL)
11166     {
11167       ClutterActor *tmp = sibling->priv->next_sibling;
11168
11169       child->priv->next_sibling = tmp;
11170
11171       if (tmp != NULL)
11172         tmp->priv->prev_sibling = child;
11173
11174       sibling->priv->next_sibling = child;
11175     }
11176   else
11177     child->priv->next_sibling = NULL;
11178
11179   if (child->priv->prev_sibling == NULL)
11180     self->priv->first_child = child;
11181
11182   if (child->priv->next_sibling == NULL)
11183     self->priv->last_child = child;
11184 }
11185
11186 static void
11187 insert_child_below (ClutterActor *self,
11188                     ClutterActor *child,
11189                     gpointer      data)
11190 {
11191   ClutterActor *sibling = data;
11192
11193   child->priv->parent = self;
11194
11195   if (sibling == NULL)
11196     sibling = self->priv->first_child;
11197
11198   child->priv->next_sibling = sibling;
11199
11200   if (sibling != NULL)
11201     {
11202       ClutterActor *tmp = sibling->priv->prev_sibling;
11203
11204       child->priv->prev_sibling = tmp;
11205
11206       if (tmp != NULL)
11207         tmp->priv->next_sibling = child;
11208
11209       sibling->priv->prev_sibling = child;
11210     }
11211   else
11212     child->priv->prev_sibling = NULL;
11213
11214   if (child->priv->prev_sibling == NULL)
11215     self->priv->first_child = child;
11216
11217   if (child->priv->next_sibling == NULL)
11218     self->priv->last_child = child;
11219 }
11220
11221 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11222                                            ClutterActor *child,
11223                                            gpointer      data);
11224
11225 typedef enum {
11226   ADD_CHILD_CREATE_META        = 1 << 0,
11227   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11228   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11229   ADD_CHILD_CHECK_STATE        = 1 << 3,
11230   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11231   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11232
11233   /* default flags for public API */
11234   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11235                                ADD_CHILD_EMIT_PARENT_SET |
11236                                ADD_CHILD_EMIT_ACTOR_ADDED |
11237                                ADD_CHILD_CHECK_STATE |
11238                                ADD_CHILD_NOTIFY_FIRST_LAST |
11239                                ADD_CHILD_SHOW_ON_SET_PARENT,
11240
11241   /* flags for legacy/deprecated API */
11242   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11243                                ADD_CHILD_CHECK_STATE |
11244                                ADD_CHILD_NOTIFY_FIRST_LAST |
11245                                ADD_CHILD_SHOW_ON_SET_PARENT
11246 } ClutterActorAddChildFlags;
11247
11248 /*< private >
11249  * clutter_actor_add_child_internal:
11250  * @self: a #ClutterActor
11251  * @child: a #ClutterActor
11252  * @flags: control flags for actions
11253  * @add_func: delegate function
11254  * @data: (closure): data to pass to @add_func
11255  *
11256  * Adds @child to the list of children of @self.
11257  *
11258  * The actual insertion inside the list is delegated to @add_func: this
11259  * function will just set up the state, perform basic checks, and emit
11260  * signals.
11261  *
11262  * The @flags argument is used to perform additional operations.
11263  */
11264 static inline void
11265 clutter_actor_add_child_internal (ClutterActor              *self,
11266                                   ClutterActor              *child,
11267                                   ClutterActorAddChildFlags  flags,
11268                                   ClutterActorAddChildFunc   add_func,
11269                                   gpointer                   data)
11270 {
11271   ClutterTextDirection text_dir;
11272   gboolean create_meta;
11273   gboolean emit_parent_set, emit_actor_added;
11274   gboolean check_state;
11275   gboolean notify_first_last;
11276   gboolean show_on_set_parent;
11277   ClutterActor *old_first_child, *old_last_child;
11278
11279   if (child->priv->parent != NULL)
11280     {
11281       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11282                  "use clutter_actor_remove_child() first.",
11283                  _clutter_actor_get_debug_name (child),
11284                  _clutter_actor_get_debug_name (child->priv->parent));
11285       return;
11286     }
11287
11288   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11289     {
11290       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11291                  "a child of another actor.",
11292                  _clutter_actor_get_debug_name (child));
11293       return;
11294     }
11295
11296 #if 0
11297   /* XXX - this check disallows calling methods that change the stacking
11298    * order within the destruction sequence, by triggering a critical
11299    * warning first, and leaving the actor in an undefined state, which
11300    * then ends up being caught by an assertion.
11301    *
11302    * the reproducible sequence is:
11303    *
11304    *   - actor gets destroyed;
11305    *   - another actor, linked to the first, will try to change the
11306    *     stacking order of the first actor;
11307    *   - changing the stacking order is a composite operation composed
11308    *     by the following steps:
11309    *     1. ref() the child;
11310    *     2. remove_child_internal(), which removes the reference;
11311    *     3. add_child_internal(), which adds a reference;
11312    *   - the state of the actor is not changed between (2) and (3), as
11313    *     it could be an expensive recomputation;
11314    *   - if (3) bails out, then the actor is in an undefined state, but
11315    *     still alive;
11316    *   - the destruction sequence terminates, but the actor is unparented
11317    *     while its state indicates being parented instead.
11318    *   - assertion failure.
11319    *
11320    * the obvious fix would be to decompose each set_child_*_sibling()
11321    * method into proper remove_child()/add_child(), with state validation;
11322    * this may cause excessive work, though, and trigger a cascade of other
11323    * bugs in code that assumes that a change in the stacking order is an
11324    * atomic operation.
11325    *
11326    * another potential fix is to just remove this check here, and let
11327    * code doing stacking order changes inside the destruction sequence
11328    * of an actor continue doing the work.
11329    *
11330    * the third fix is to silently bail out early from every
11331    * set_child_*_sibling() and set_child_at_index() method, and avoid
11332    * doing work.
11333    *
11334    * I have a preference for the second solution, since it involves the
11335    * least amount of work, and the least amount of code duplication.
11336    *
11337    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11338    */
11339   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11340     {
11341       g_warning ("The actor '%s' is currently being destroyed, and "
11342                  "cannot be added as a child of another actor.",
11343                  _clutter_actor_get_debug_name (child));
11344       return;
11345     }
11346 #endif
11347
11348   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11349   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11350   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11351   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11352   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11353   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11354
11355   old_first_child = self->priv->first_child;
11356   old_last_child = self->priv->last_child;
11357
11358   g_object_freeze_notify (G_OBJECT (self));
11359
11360   if (create_meta)
11361     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11362
11363   g_object_ref_sink (child);
11364   child->priv->parent = NULL;
11365   child->priv->next_sibling = NULL;
11366   child->priv->prev_sibling = NULL;
11367
11368   /* delegate the actual insertion */
11369   add_func (self, child, data);
11370
11371   g_assert (child->priv->parent == self);
11372
11373   self->priv->n_children += 1;
11374
11375   self->priv->age += 1;
11376
11377   /* if push_internal() has been called then we automatically set
11378    * the flag on the actor
11379    */
11380   if (self->priv->internal_child)
11381     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11382
11383   /* children may cause their parent to expand, if they are set
11384    * to expand; if a child is not expanded then it cannot change
11385    * its parent's state. any further change later on will queue
11386    * an expand state check.
11387    *
11388    * this check, with the initial state of the needs_compute_expand
11389    * flag set to FALSE, should avoid recomputing the expand flags
11390    * state while building the actor tree.
11391    */
11392   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11393       (child->priv->needs_compute_expand ||
11394        child->priv->needs_x_expand ||
11395        child->priv->needs_y_expand))
11396     {
11397       clutter_actor_queue_compute_expand (self);
11398     }
11399
11400   /* clutter_actor_reparent() will emit ::parent-set for us */
11401   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11402     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11403
11404   if (check_state)
11405     {
11406       /* If parent is mapped or realized, we need to also be mapped or
11407        * realized once we're inside the parent.
11408        */
11409       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11410
11411       /* propagate the parent's text direction to the child */
11412       text_dir = clutter_actor_get_text_direction (self);
11413       clutter_actor_set_text_direction (child, text_dir);
11414     }
11415
11416   if (show_on_set_parent && child->priv->show_on_set_parent)
11417     clutter_actor_show (child);
11418
11419   if (CLUTTER_ACTOR_IS_MAPPED (child))
11420     clutter_actor_queue_redraw (child);
11421
11422   /* maintain the invariant that if an actor needs layout,
11423    * its parents do as well
11424    */
11425   if (child->priv->needs_width_request ||
11426       child->priv->needs_height_request ||
11427       child->priv->needs_allocation)
11428     {
11429       /* we work around the short-circuiting we do
11430        * in clutter_actor_queue_relayout() since we
11431        * want to force a relayout
11432        */
11433       child->priv->needs_width_request = TRUE;
11434       child->priv->needs_height_request = TRUE;
11435       child->priv->needs_allocation = TRUE;
11436
11437       clutter_actor_queue_relayout (child->priv->parent);
11438     }
11439
11440   if (emit_actor_added)
11441     g_signal_emit_by_name (self, "actor-added", child);
11442
11443   if (notify_first_last)
11444     {
11445       if (old_first_child != self->priv->first_child)
11446         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11447
11448       if (old_last_child != self->priv->last_child)
11449         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11450     }
11451
11452   g_object_thaw_notify (G_OBJECT (self));
11453 }
11454
11455 /**
11456  * clutter_actor_add_child:
11457  * @self: a #ClutterActor
11458  * @child: a #ClutterActor
11459  *
11460  * Adds @child to the children of @self.
11461  *
11462  * This function will acquire a reference on @child that will only
11463  * be released when calling clutter_actor_remove_child().
11464  *
11465  * This function will take into consideration the #ClutterActor:depth
11466  * of @child, and will keep the list of children sorted.
11467  *
11468  * This function will emit the #ClutterContainer::actor-added signal
11469  * on @self.
11470  *
11471  * Since: 1.10
11472  */
11473 void
11474 clutter_actor_add_child (ClutterActor *self,
11475                          ClutterActor *child)
11476 {
11477   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11478   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11479   g_return_if_fail (self != child);
11480   g_return_if_fail (child->priv->parent == NULL);
11481
11482   clutter_actor_add_child_internal (self, child,
11483                                     ADD_CHILD_DEFAULT_FLAGS,
11484                                     insert_child_at_depth,
11485                                     NULL);
11486 }
11487
11488 /**
11489  * clutter_actor_insert_child_at_index:
11490  * @self: a #ClutterActor
11491  * @child: a #ClutterActor
11492  * @index_: the index
11493  *
11494  * Inserts @child into the list of children of @self, using the
11495  * given @index_. If @index_ is greater than the number of children
11496  * in @self, or is less than 0, then the new child is added at the end.
11497  *
11498  * This function will acquire a reference on @child that will only
11499  * be released when calling clutter_actor_remove_child().
11500  *
11501  * This function will not take into consideration the #ClutterActor:depth
11502  * of @child.
11503  *
11504  * This function will emit the #ClutterContainer::actor-added signal
11505  * on @self.
11506  *
11507  * Since: 1.10
11508  */
11509 void
11510 clutter_actor_insert_child_at_index (ClutterActor *self,
11511                                      ClutterActor *child,
11512                                      gint          index_)
11513 {
11514   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11515   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11516   g_return_if_fail (self != child);
11517   g_return_if_fail (child->priv->parent == NULL);
11518
11519   clutter_actor_add_child_internal (self, child,
11520                                     ADD_CHILD_DEFAULT_FLAGS,
11521                                     insert_child_at_index,
11522                                     GINT_TO_POINTER (index_));
11523 }
11524
11525 /**
11526  * clutter_actor_insert_child_above:
11527  * @self: a #ClutterActor
11528  * @child: a #ClutterActor
11529  * @sibling: (allow-none): a child of @self, or %NULL
11530  *
11531  * Inserts @child into the list of children of @self, above another
11532  * child of @self or, if @sibling is %NULL, above all the children
11533  * of @self.
11534  *
11535  * This function will acquire a reference on @child that will only
11536  * be released when calling clutter_actor_remove_child().
11537  *
11538  * This function will not take into consideration the #ClutterActor:depth
11539  * of @child.
11540  *
11541  * This function will emit the #ClutterContainer::actor-added signal
11542  * on @self.
11543  *
11544  * Since: 1.10
11545  */
11546 void
11547 clutter_actor_insert_child_above (ClutterActor *self,
11548                                   ClutterActor *child,
11549                                   ClutterActor *sibling)
11550 {
11551   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11552   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11553   g_return_if_fail (self != child);
11554   g_return_if_fail (child != sibling);
11555   g_return_if_fail (child->priv->parent == NULL);
11556   g_return_if_fail (sibling == NULL ||
11557                     (CLUTTER_IS_ACTOR (sibling) &&
11558                      sibling->priv->parent == self));
11559
11560   clutter_actor_add_child_internal (self, child,
11561                                     ADD_CHILD_DEFAULT_FLAGS,
11562                                     insert_child_above,
11563                                     sibling);
11564 }
11565
11566 /**
11567  * clutter_actor_insert_child_below:
11568  * @self: a #ClutterActor
11569  * @child: a #ClutterActor
11570  * @sibling: (allow-none): a child of @self, or %NULL
11571  *
11572  * Inserts @child into the list of children of @self, below another
11573  * child of @self or, if @sibling is %NULL, below all the children
11574  * of @self.
11575  *
11576  * This function will acquire a reference on @child that will only
11577  * be released when calling clutter_actor_remove_child().
11578  *
11579  * This function will not take into consideration the #ClutterActor:depth
11580  * of @child.
11581  *
11582  * This function will emit the #ClutterContainer::actor-added signal
11583  * on @self.
11584  *
11585  * Since: 1.10
11586  */
11587 void
11588 clutter_actor_insert_child_below (ClutterActor *self,
11589                                   ClutterActor *child,
11590                                   ClutterActor *sibling)
11591 {
11592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11593   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11594   g_return_if_fail (self != child);
11595   g_return_if_fail (child != sibling);
11596   g_return_if_fail (child->priv->parent == NULL);
11597   g_return_if_fail (sibling == NULL ||
11598                     (CLUTTER_IS_ACTOR (sibling) &&
11599                      sibling->priv->parent == self));
11600
11601   clutter_actor_add_child_internal (self, child,
11602                                     ADD_CHILD_DEFAULT_FLAGS,
11603                                     insert_child_below,
11604                                     sibling);
11605 }
11606
11607 /**
11608  * clutter_actor_set_parent:
11609  * @self: A #ClutterActor
11610  * @parent: A new #ClutterActor parent
11611  *
11612  * Sets the parent of @self to @parent.
11613  *
11614  * This function will result in @parent acquiring a reference on @self,
11615  * eventually by sinking its floating reference first. The reference
11616  * will be released by clutter_actor_unparent().
11617  *
11618  * This function should only be called by legacy #ClutterActor<!-- -->s
11619  * implementing the #ClutterContainer interface.
11620  *
11621  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11622  */
11623 void
11624 clutter_actor_set_parent (ClutterActor *self,
11625                           ClutterActor *parent)
11626 {
11627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11628   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11629   g_return_if_fail (self != parent);
11630   g_return_if_fail (self->priv->parent == NULL);
11631
11632   /* as this function will be called inside ClutterContainer::add
11633    * implementations or when building up a composite actor, we have
11634    * to preserve the old behaviour, and not create child meta or
11635    * emit the ::actor-added signal, to avoid recursion or double
11636    * emissions
11637    */
11638   clutter_actor_add_child_internal (parent, self,
11639                                     ADD_CHILD_LEGACY_FLAGS,
11640                                     insert_child_at_depth,
11641                                     NULL);
11642 }
11643
11644 /**
11645  * clutter_actor_get_parent:
11646  * @self: A #ClutterActor
11647  *
11648  * Retrieves the parent of @self.
11649  *
11650  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11651  *  if no parent is set
11652  */
11653 ClutterActor *
11654 clutter_actor_get_parent (ClutterActor *self)
11655 {
11656   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11657
11658   return self->priv->parent;
11659 }
11660
11661 /**
11662  * clutter_actor_get_paint_visibility:
11663  * @self: A #ClutterActor
11664  *
11665  * Retrieves the 'paint' visibility of an actor recursively checking for non
11666  * visible parents.
11667  *
11668  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11669  *
11670  * Return Value: %TRUE if the actor is visibile and will be painted.
11671  *
11672  * Since: 0.8.4
11673  */
11674 gboolean
11675 clutter_actor_get_paint_visibility (ClutterActor *actor)
11676 {
11677   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11678
11679   return CLUTTER_ACTOR_IS_MAPPED (actor);
11680 }
11681
11682 /**
11683  * clutter_actor_remove_child:
11684  * @self: a #ClutterActor
11685  * @child: a #ClutterActor
11686  *
11687  * Removes @child from the children of @self.
11688  *
11689  * This function will release the reference added by
11690  * clutter_actor_add_child(), so if you want to keep using @child
11691  * you will have to acquire a referenced on it before calling this
11692  * function.
11693  *
11694  * This function will emit the #ClutterContainer::actor-removed
11695  * signal on @self.
11696  *
11697  * Since: 1.10
11698  */
11699 void
11700 clutter_actor_remove_child (ClutterActor *self,
11701                             ClutterActor *child)
11702 {
11703   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11704   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11705   g_return_if_fail (self != child);
11706   g_return_if_fail (child->priv->parent != NULL);
11707   g_return_if_fail (child->priv->parent == self);
11708
11709   clutter_actor_remove_child_internal (self, child,
11710                                        REMOVE_CHILD_DEFAULT_FLAGS);
11711 }
11712
11713 /**
11714  * clutter_actor_remove_all_children:
11715  * @self: a #ClutterActor
11716  *
11717  * Removes all children of @self.
11718  *
11719  * This function releases the reference added by inserting a child actor
11720  * in the list of children of @self.
11721  *
11722  * If the reference count of a child drops to zero, the child will be
11723  * destroyed. If you want to ensure the destruction of all the children
11724  * of @self, use clutter_actor_destroy_all_children().
11725  *
11726  * Since: 1.10
11727  */
11728 void
11729 clutter_actor_remove_all_children (ClutterActor *self)
11730 {
11731   ClutterActorIter iter;
11732
11733   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11734
11735   if (self->priv->n_children == 0)
11736     return;
11737
11738   g_object_freeze_notify (G_OBJECT (self));
11739
11740   clutter_actor_iter_init (&iter, self);
11741   while (clutter_actor_iter_next (&iter, NULL))
11742     clutter_actor_iter_remove (&iter);
11743
11744   g_object_thaw_notify (G_OBJECT (self));
11745
11746   /* sanity check */
11747   g_assert (self->priv->first_child == NULL);
11748   g_assert (self->priv->last_child == NULL);
11749   g_assert (self->priv->n_children == 0);
11750 }
11751
11752 /**
11753  * clutter_actor_destroy_all_children:
11754  * @self: a #ClutterActor
11755  *
11756  * Destroys all children of @self.
11757  *
11758  * This function releases the reference added by inserting a child
11759  * actor in the list of children of @self, and ensures that the
11760  * #ClutterActor::destroy signal is emitted on each child of the
11761  * actor.
11762  *
11763  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11764  * when its reference count drops to 0; the default handler of the
11765  * #ClutterActor::destroy signal will destroy all the children of an
11766  * actor. This function ensures that all children are destroyed, instead
11767  * of just removed from @self, unlike clutter_actor_remove_all_children()
11768  * which will merely release the reference and remove each child.
11769  *
11770  * Unless you acquired an additional reference on each child of @self
11771  * prior to calling clutter_actor_remove_all_children() and want to reuse
11772  * the actors, you should use clutter_actor_destroy_all_children() in
11773  * order to make sure that children are destroyed and signal handlers
11774  * are disconnected even in cases where circular references prevent this
11775  * from automatically happening through reference counting alone.
11776  *
11777  * Since: 1.10
11778  */
11779 void
11780 clutter_actor_destroy_all_children (ClutterActor *self)
11781 {
11782   ClutterActorIter iter;
11783
11784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11785
11786   if (self->priv->n_children == 0)
11787     return;
11788
11789   g_object_freeze_notify (G_OBJECT (self));
11790
11791   clutter_actor_iter_init (&iter, self);
11792   while (clutter_actor_iter_next (&iter, NULL))
11793     clutter_actor_iter_destroy (&iter);
11794
11795   g_object_thaw_notify (G_OBJECT (self));
11796
11797   /* sanity check */
11798   g_assert (self->priv->first_child == NULL);
11799   g_assert (self->priv->last_child == NULL);
11800   g_assert (self->priv->n_children == 0);
11801 }
11802
11803 typedef struct _InsertBetweenData {
11804   ClutterActor *prev_sibling;
11805   ClutterActor *next_sibling;
11806 } InsertBetweenData;
11807
11808 static void
11809 insert_child_between (ClutterActor *self,
11810                       ClutterActor *child,
11811                       gpointer      data_)
11812 {
11813   InsertBetweenData *data = data_;
11814   ClutterActor *prev_sibling = data->prev_sibling;
11815   ClutterActor *next_sibling = data->next_sibling;
11816
11817   child->priv->parent = self;
11818   child->priv->prev_sibling = prev_sibling;
11819   child->priv->next_sibling = next_sibling;
11820
11821   if (prev_sibling != NULL)
11822     prev_sibling->priv->next_sibling = child;
11823
11824   if (next_sibling != NULL)
11825     next_sibling->priv->prev_sibling = child;
11826
11827   if (child->priv->prev_sibling == NULL)
11828     self->priv->first_child = child;
11829
11830   if (child->priv->next_sibling == NULL)
11831     self->priv->last_child = child;
11832 }
11833
11834 /**
11835  * clutter_actor_replace_child:
11836  * @self: a #ClutterActor
11837  * @old_child: the child of @self to replace
11838  * @new_child: the #ClutterActor to replace @old_child
11839  *
11840  * Replaces @old_child with @new_child in the list of children of @self.
11841  *
11842  * Since: 1.10
11843  */
11844 void
11845 clutter_actor_replace_child (ClutterActor *self,
11846                              ClutterActor *old_child,
11847                              ClutterActor *new_child)
11848 {
11849   ClutterActor *prev_sibling, *next_sibling;
11850   InsertBetweenData clos;
11851
11852   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11853   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11854   g_return_if_fail (old_child->priv->parent == self);
11855   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11856   g_return_if_fail (old_child != new_child);
11857   g_return_if_fail (new_child != self);
11858   g_return_if_fail (new_child->priv->parent == NULL);
11859
11860   prev_sibling = old_child->priv->prev_sibling;
11861   next_sibling = old_child->priv->next_sibling;
11862   clutter_actor_remove_child_internal (self, old_child,
11863                                        REMOVE_CHILD_DEFAULT_FLAGS);
11864
11865   clos.prev_sibling = prev_sibling;
11866   clos.next_sibling = next_sibling;
11867   clutter_actor_add_child_internal (self, new_child,
11868                                     ADD_CHILD_DEFAULT_FLAGS,
11869                                     insert_child_between,
11870                                     &clos);
11871 }
11872
11873 /**
11874  * clutter_actor_unparent:
11875  * @self: a #ClutterActor
11876  *
11877  * Removes the parent of @self.
11878  *
11879  * This will cause the parent of @self to release the reference
11880  * acquired when calling clutter_actor_set_parent(), so if you
11881  * want to keep @self you will have to acquire a reference of
11882  * your own, through g_object_ref().
11883  *
11884  * This function should only be called by legacy #ClutterActor<!-- -->s
11885  * implementing the #ClutterContainer interface.
11886  *
11887  * Since: 0.1.1
11888  *
11889  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11890  */
11891 void
11892 clutter_actor_unparent (ClutterActor *self)
11893 {
11894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11895
11896   if (self->priv->parent == NULL)
11897     return;
11898
11899   clutter_actor_remove_child_internal (self->priv->parent, self,
11900                                        REMOVE_CHILD_LEGACY_FLAGS);
11901 }
11902
11903 /**
11904  * clutter_actor_reparent:
11905  * @self: a #ClutterActor
11906  * @new_parent: the new #ClutterActor parent
11907  *
11908  * Resets the parent actor of @self.
11909  *
11910  * This function is logically equivalent to calling clutter_actor_unparent()
11911  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11912  * ensures the child is not finalized when unparented, and emits the
11913  * #ClutterActor::parent-set signal only once.
11914  *
11915  * In reality, calling this function is less useful than it sounds, as some
11916  * application code may rely on changes in the intermediate state between
11917  * removal and addition of the actor from its old parent to the @new_parent.
11918  * Thus, it is strongly encouraged to avoid using this function in application
11919  * code.
11920  *
11921  * Since: 0.2
11922  *
11923  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11924  *   clutter_actor_add_child() instead; remember to take a reference on
11925  *   the actor being removed before calling clutter_actor_remove_child()
11926  *   to avoid the reference count dropping to zero and the actor being
11927  *   destroyed.
11928  */
11929 void
11930 clutter_actor_reparent (ClutterActor *self,
11931                         ClutterActor *new_parent)
11932 {
11933   ClutterActorPrivate *priv;
11934
11935   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11936   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11937   g_return_if_fail (self != new_parent);
11938
11939   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11940     {
11941       g_warning ("Cannot set a parent on a toplevel actor");
11942       return;
11943     }
11944
11945   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11946     {
11947       g_warning ("Cannot set a parent currently being destroyed");
11948       return;
11949     }
11950
11951   priv = self->priv;
11952
11953   if (priv->parent != new_parent)
11954     {
11955       ClutterActor *old_parent;
11956
11957       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11958
11959       old_parent = priv->parent;
11960
11961       g_object_ref (self);
11962
11963       if (old_parent != NULL)
11964         {
11965          /* go through the Container implementation if this is a regular
11966           * child and not an internal one
11967           */
11968          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11969            {
11970              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11971
11972              /* this will have to call unparent() */
11973              clutter_container_remove_actor (parent, self);
11974            }
11975          else
11976            clutter_actor_remove_child_internal (old_parent, self,
11977                                                 REMOVE_CHILD_LEGACY_FLAGS);
11978         }
11979
11980       /* Note, will call set_parent() */
11981       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11982         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11983       else
11984         clutter_actor_add_child_internal (new_parent, self,
11985                                           ADD_CHILD_LEGACY_FLAGS,
11986                                           insert_child_at_depth,
11987                                           NULL);
11988
11989       /* we emit the ::parent-set signal once */
11990       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11991
11992       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11993
11994       /* the IN_REPARENT flag suspends state updates */
11995       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11996
11997       g_object_unref (self);
11998    }
11999 }
12000
12001 /**
12002  * clutter_actor_contains:
12003  * @self: A #ClutterActor
12004  * @descendant: A #ClutterActor, possibly contained in @self
12005  *
12006  * Determines if @descendant is contained inside @self (either as an
12007  * immediate child, or as a deeper descendant). If @self and
12008  * @descendant point to the same actor then it will also return %TRUE.
12009  *
12010  * Return value: whether @descendent is contained within @self
12011  *
12012  * Since: 1.4
12013  */
12014 gboolean
12015 clutter_actor_contains (ClutterActor *self,
12016                         ClutterActor *descendant)
12017 {
12018   ClutterActor *actor;
12019
12020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12021   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12022
12023   for (actor = descendant; actor; actor = actor->priv->parent)
12024     if (actor == self)
12025       return TRUE;
12026
12027   return FALSE;
12028 }
12029
12030 /**
12031  * clutter_actor_set_child_above_sibling:
12032  * @self: a #ClutterActor
12033  * @child: a #ClutterActor child of @self
12034  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12035  *
12036  * Sets @child to be above @sibling in the list of children of @self.
12037  *
12038  * If @sibling is %NULL, @child will be the new last child of @self.
12039  *
12040  * This function is logically equivalent to removing @child and using
12041  * clutter_actor_insert_child_above(), but it will not emit signals
12042  * or change state on @child.
12043  *
12044  * Since: 1.10
12045  */
12046 void
12047 clutter_actor_set_child_above_sibling (ClutterActor *self,
12048                                        ClutterActor *child,
12049                                        ClutterActor *sibling)
12050 {
12051   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12052   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12053   g_return_if_fail (child->priv->parent == self);
12054   g_return_if_fail (child != sibling);
12055   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12056
12057   if (sibling != NULL)
12058     g_return_if_fail (sibling->priv->parent == self);
12059
12060   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12061       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12062       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12063     return;
12064
12065   /* we don't want to change the state of child, or emit signals, or
12066    * regenerate ChildMeta instances here, but we still want to follow
12067    * the correct sequence of steps encoded in remove_child() and
12068    * add_child(), so that correctness is ensured, and we only go
12069    * through one known code path.
12070    */
12071   g_object_ref (child);
12072   clutter_actor_remove_child_internal (self, child, 0);
12073   clutter_actor_add_child_internal (self, child,
12074                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12075                                     insert_child_above,
12076                                     sibling);
12077
12078   clutter_actor_queue_relayout (self);
12079 }
12080
12081 /**
12082  * clutter_actor_set_child_below_sibling:
12083  * @self: a #ClutterActor
12084  * @child: a #ClutterActor child of @self
12085  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12086  *
12087  * Sets @child to be below @sibling in the list of children of @self.
12088  *
12089  * If @sibling is %NULL, @child will be the new first child of @self.
12090  *
12091  * This function is logically equivalent to removing @self and using
12092  * clutter_actor_insert_child_below(), but it will not emit signals
12093  * or change state on @child.
12094  *
12095  * Since: 1.10
12096  */
12097 void
12098 clutter_actor_set_child_below_sibling (ClutterActor *self,
12099                                        ClutterActor *child,
12100                                        ClutterActor *sibling)
12101 {
12102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12103   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12104   g_return_if_fail (child->priv->parent == self);
12105   g_return_if_fail (child != sibling);
12106   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12107
12108   if (sibling != NULL)
12109     g_return_if_fail (sibling->priv->parent == self);
12110
12111   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12112       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12113       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12114     return;
12115
12116   /* see the comment in set_child_above_sibling() */
12117   g_object_ref (child);
12118   clutter_actor_remove_child_internal (self, child, 0);
12119   clutter_actor_add_child_internal (self, child,
12120                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12121                                     insert_child_below,
12122                                     sibling);
12123
12124   clutter_actor_queue_relayout (self);
12125 }
12126
12127 /**
12128  * clutter_actor_set_child_at_index:
12129  * @self: a #ClutterActor
12130  * @child: a #ClutterActor child of @self
12131  * @index_: the new index for @child
12132  *
12133  * Changes the index of @child in the list of children of @self.
12134  *
12135  * This function is logically equivalent to removing @child and
12136  * calling clutter_actor_insert_child_at_index(), but it will not
12137  * emit signals or change state on @child.
12138  *
12139  * Since: 1.10
12140  */
12141 void
12142 clutter_actor_set_child_at_index (ClutterActor *self,
12143                                   ClutterActor *child,
12144                                   gint          index_)
12145 {
12146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12147   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12148   g_return_if_fail (child->priv->parent == self);
12149   g_return_if_fail (index_ <= self->priv->n_children);
12150
12151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12152       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12153     return;
12154
12155   g_object_ref (child);
12156   clutter_actor_remove_child_internal (self, child, 0);
12157   clutter_actor_add_child_internal (self, child,
12158                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12159                                     insert_child_at_index,
12160                                     GINT_TO_POINTER (index_));
12161
12162   clutter_actor_queue_relayout (self);
12163 }
12164
12165 /**
12166  * clutter_actor_raise:
12167  * @self: A #ClutterActor
12168  * @below: (allow-none): A #ClutterActor to raise above.
12169  *
12170  * Puts @self above @below.
12171  *
12172  * Both actors must have the same parent, and the parent must implement
12173  * the #ClutterContainer interface
12174  *
12175  * This function calls clutter_container_raise_child() internally.
12176  *
12177  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12178  */
12179 void
12180 clutter_actor_raise (ClutterActor *self,
12181                      ClutterActor *below)
12182 {
12183   ClutterActor *parent;
12184
12185   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12186
12187   parent = clutter_actor_get_parent (self);
12188   if (parent == NULL)
12189     {
12190       g_warning ("%s: Actor '%s' is not inside a container",
12191                  G_STRFUNC,
12192                  _clutter_actor_get_debug_name (self));
12193       return;
12194     }
12195
12196   if (below != NULL)
12197     {
12198       if (parent != clutter_actor_get_parent (below))
12199         {
12200           g_warning ("%s Actor '%s' is not in the same container as "
12201                      "actor '%s'",
12202                      G_STRFUNC,
12203                      _clutter_actor_get_debug_name (self),
12204                      _clutter_actor_get_debug_name (below));
12205           return;
12206         }
12207     }
12208
12209   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12210 }
12211
12212 /**
12213  * clutter_actor_lower:
12214  * @self: A #ClutterActor
12215  * @above: (allow-none): A #ClutterActor to lower below
12216  *
12217  * Puts @self below @above.
12218  *
12219  * Both actors must have the same parent, and the parent must implement
12220  * the #ClutterContainer interface.
12221  *
12222  * This function calls clutter_container_lower_child() internally.
12223  *
12224  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12225  */
12226 void
12227 clutter_actor_lower (ClutterActor *self,
12228                      ClutterActor *above)
12229 {
12230   ClutterActor *parent;
12231
12232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12233
12234   parent = clutter_actor_get_parent (self);
12235   if (parent == NULL)
12236     {
12237       g_warning ("%s: Actor of type %s is not inside a container",
12238                  G_STRFUNC,
12239                  _clutter_actor_get_debug_name (self));
12240       return;
12241     }
12242
12243   if (above)
12244     {
12245       if (parent != clutter_actor_get_parent (above))
12246         {
12247           g_warning ("%s: Actor '%s' is not in the same container as "
12248                      "actor '%s'",
12249                      G_STRFUNC,
12250                      _clutter_actor_get_debug_name (self),
12251                      _clutter_actor_get_debug_name (above));
12252           return;
12253         }
12254     }
12255
12256   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12257 }
12258
12259 /**
12260  * clutter_actor_raise_top:
12261  * @self: A #ClutterActor
12262  *
12263  * Raises @self to the top.
12264  *
12265  * This function calls clutter_actor_raise() internally.
12266  *
12267  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12268  *   a %NULL sibling, instead.
12269  */
12270 void
12271 clutter_actor_raise_top (ClutterActor *self)
12272 {
12273   clutter_actor_raise (self, NULL);
12274 }
12275
12276 /**
12277  * clutter_actor_lower_bottom:
12278  * @self: A #ClutterActor
12279  *
12280  * Lowers @self to the bottom.
12281  *
12282  * This function calls clutter_actor_lower() internally.
12283  *
12284  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12285  *   a %NULL sibling, instead.
12286  */
12287 void
12288 clutter_actor_lower_bottom (ClutterActor *self)
12289 {
12290   clutter_actor_lower (self, NULL);
12291 }
12292
12293 /*
12294  * Event handling
12295  */
12296
12297 /**
12298  * clutter_actor_event:
12299  * @actor: a #ClutterActor
12300  * @event: a #ClutterEvent
12301  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12302  *
12303  * This function is used to emit an event on the main stage.
12304  * You should rarely need to use this function, except for
12305  * synthetising events.
12306  *
12307  * Return value: the return value from the signal emission: %TRUE
12308  *   if the actor handled the event, or %FALSE if the event was
12309  *   not handled
12310  *
12311  * Since: 0.6
12312  */
12313 gboolean
12314 clutter_actor_event (ClutterActor *actor,
12315                      ClutterEvent *event,
12316                      gboolean      capture)
12317 {
12318   gboolean retval = FALSE;
12319   gint signal_num = -1;
12320
12321   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12322   g_return_val_if_fail (event != NULL, FALSE);
12323
12324   g_object_ref (actor);
12325
12326   if (capture)
12327     {
12328       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12329                      event,
12330                      &retval);
12331       goto out;
12332     }
12333
12334   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12335
12336   if (!retval)
12337     {
12338       switch (event->type)
12339         {
12340         case CLUTTER_NOTHING:
12341           break;
12342         case CLUTTER_BUTTON_PRESS:
12343           signal_num = BUTTON_PRESS_EVENT;
12344           break;
12345         case CLUTTER_BUTTON_RELEASE:
12346           signal_num = BUTTON_RELEASE_EVENT;
12347           break;
12348         case CLUTTER_SCROLL:
12349           signal_num = SCROLL_EVENT;
12350           break;
12351         case CLUTTER_KEY_PRESS:
12352           signal_num = KEY_PRESS_EVENT;
12353           break;
12354         case CLUTTER_KEY_RELEASE:
12355           signal_num = KEY_RELEASE_EVENT;
12356           break;
12357         case CLUTTER_MOTION:
12358           signal_num = MOTION_EVENT;
12359           break;
12360         case CLUTTER_ENTER:
12361           signal_num = ENTER_EVENT;
12362           break;
12363         case CLUTTER_LEAVE:
12364           signal_num = LEAVE_EVENT;
12365           break;
12366         case CLUTTER_DELETE:
12367         case CLUTTER_DESTROY_NOTIFY:
12368         case CLUTTER_CLIENT_MESSAGE:
12369         default:
12370           signal_num = -1;
12371           break;
12372         }
12373
12374       if (signal_num != -1)
12375         g_signal_emit (actor, actor_signals[signal_num], 0,
12376                        event, &retval);
12377     }
12378
12379 out:
12380   g_object_unref (actor);
12381
12382   return retval;
12383 }
12384
12385 /**
12386  * clutter_actor_set_reactive:
12387  * @actor: a #ClutterActor
12388  * @reactive: whether the actor should be reactive to events
12389  *
12390  * Sets @actor as reactive. Reactive actors will receive events.
12391  *
12392  * Since: 0.6
12393  */
12394 void
12395 clutter_actor_set_reactive (ClutterActor *actor,
12396                             gboolean      reactive)
12397 {
12398   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12399
12400   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12401     return;
12402
12403   if (reactive)
12404     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12405   else
12406     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12407
12408   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12409 }
12410
12411 /**
12412  * clutter_actor_get_reactive:
12413  * @actor: a #ClutterActor
12414  *
12415  * Checks whether @actor is marked as reactive.
12416  *
12417  * Return value: %TRUE if the actor is reactive
12418  *
12419  * Since: 0.6
12420  */
12421 gboolean
12422 clutter_actor_get_reactive (ClutterActor *actor)
12423 {
12424   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12425
12426   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12427 }
12428
12429 /**
12430  * clutter_actor_get_anchor_point:
12431  * @self: a #ClutterActor
12432  * @anchor_x: (out): return location for the X coordinate of the anchor point
12433  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12434  *
12435  * Gets the current anchor point of the @actor in pixels.
12436  *
12437  * Since: 0.6
12438  */
12439 void
12440 clutter_actor_get_anchor_point (ClutterActor *self,
12441                                 gfloat       *anchor_x,
12442                                 gfloat       *anchor_y)
12443 {
12444   const ClutterTransformInfo *info;
12445
12446   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12447
12448   info = _clutter_actor_get_transform_info_or_defaults (self);
12449   clutter_anchor_coord_get_units (self, &info->anchor,
12450                                   anchor_x,
12451                                   anchor_y,
12452                                   NULL);
12453 }
12454
12455 /**
12456  * clutter_actor_set_anchor_point:
12457  * @self: a #ClutterActor
12458  * @anchor_x: X coordinate of the anchor point
12459  * @anchor_y: Y coordinate of the anchor point
12460  *
12461  * Sets an anchor point for @self. The anchor point is a point in the
12462  * coordinate space of an actor to which the actor position within its
12463  * parent is relative; the default is (0, 0), i.e. the top-left corner
12464  * of the actor.
12465  *
12466  * Since: 0.6
12467  */
12468 void
12469 clutter_actor_set_anchor_point (ClutterActor *self,
12470                                 gfloat        anchor_x,
12471                                 gfloat        anchor_y)
12472 {
12473   ClutterTransformInfo *info;
12474   ClutterActorPrivate *priv;
12475   gboolean changed = FALSE;
12476   gfloat old_anchor_x, old_anchor_y;
12477   GObject *obj;
12478
12479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12480
12481   obj = G_OBJECT (self);
12482   priv = self->priv;
12483   info = _clutter_actor_get_transform_info (self);
12484
12485   g_object_freeze_notify (obj);
12486
12487   clutter_anchor_coord_get_units (self, &info->anchor,
12488                                   &old_anchor_x,
12489                                   &old_anchor_y,
12490                                   NULL);
12491
12492   if (info->anchor.is_fractional)
12493     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12494
12495   if (old_anchor_x != anchor_x)
12496     {
12497       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12498       changed = TRUE;
12499     }
12500
12501   if (old_anchor_y != anchor_y)
12502     {
12503       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12504       changed = TRUE;
12505     }
12506
12507   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12508
12509   if (changed)
12510     {
12511       priv->transform_valid = FALSE;
12512       clutter_actor_queue_redraw (self);
12513     }
12514
12515   g_object_thaw_notify (obj);
12516 }
12517
12518 /**
12519  * clutter_actor_get_anchor_point_gravity:
12520  * @self: a #ClutterActor
12521  *
12522  * Retrieves the anchor position expressed as a #ClutterGravity. If
12523  * the anchor point was specified using pixels or units this will
12524  * return %CLUTTER_GRAVITY_NONE.
12525  *
12526  * Return value: the #ClutterGravity used by the anchor point
12527  *
12528  * Since: 1.0
12529  */
12530 ClutterGravity
12531 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12532 {
12533   const ClutterTransformInfo *info;
12534
12535   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12536
12537   info = _clutter_actor_get_transform_info_or_defaults (self);
12538
12539   return clutter_anchor_coord_get_gravity (&info->anchor);
12540 }
12541
12542 /**
12543  * clutter_actor_move_anchor_point:
12544  * @self: a #ClutterActor
12545  * @anchor_x: X coordinate of the anchor point
12546  * @anchor_y: Y coordinate of the anchor point
12547  *
12548  * Sets an anchor point for the actor, and adjusts the actor postion so that
12549  * the relative position of the actor toward its parent remains the same.
12550  *
12551  * Since: 0.6
12552  */
12553 void
12554 clutter_actor_move_anchor_point (ClutterActor *self,
12555                                  gfloat        anchor_x,
12556                                  gfloat        anchor_y)
12557 {
12558   gfloat old_anchor_x, old_anchor_y;
12559   const ClutterTransformInfo *info;
12560
12561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12562
12563   info = _clutter_actor_get_transform_info (self);
12564   clutter_anchor_coord_get_units (self, &info->anchor,
12565                                   &old_anchor_x,
12566                                   &old_anchor_y,
12567                                   NULL);
12568
12569   g_object_freeze_notify (G_OBJECT (self));
12570
12571   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12572
12573   if (self->priv->position_set)
12574     clutter_actor_move_by (self,
12575                            anchor_x - old_anchor_x,
12576                            anchor_y - old_anchor_y);
12577
12578   g_object_thaw_notify (G_OBJECT (self));
12579 }
12580
12581 /**
12582  * clutter_actor_move_anchor_point_from_gravity:
12583  * @self: a #ClutterActor
12584  * @gravity: #ClutterGravity.
12585  *
12586  * Sets an anchor point on the actor based on the given gravity, adjusting the
12587  * actor postion so that its relative position within its parent remains
12588  * unchanged.
12589  *
12590  * Since version 1.0 the anchor point will be stored as a gravity so
12591  * that if the actor changes size then the anchor point will move. For
12592  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12593  * and later double the size of the actor, the anchor point will move
12594  * to the bottom right.
12595  *
12596  * Since: 0.6
12597  */
12598 void
12599 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12600                                               ClutterGravity  gravity)
12601 {
12602   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12603   const ClutterTransformInfo *info;
12604   ClutterActorPrivate *priv;
12605
12606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12607
12608   priv = self->priv;
12609   info = _clutter_actor_get_transform_info (self);
12610
12611   g_object_freeze_notify (G_OBJECT (self));
12612
12613   clutter_anchor_coord_get_units (self, &info->anchor,
12614                                   &old_anchor_x,
12615                                   &old_anchor_y,
12616                                   NULL);
12617   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12618   clutter_anchor_coord_get_units (self, &info->anchor,
12619                                   &new_anchor_x,
12620                                   &new_anchor_y,
12621                                   NULL);
12622
12623   if (priv->position_set)
12624     clutter_actor_move_by (self,
12625                            new_anchor_x - old_anchor_x,
12626                            new_anchor_y - old_anchor_y);
12627
12628   g_object_thaw_notify (G_OBJECT (self));
12629 }
12630
12631 /**
12632  * clutter_actor_set_anchor_point_from_gravity:
12633  * @self: a #ClutterActor
12634  * @gravity: #ClutterGravity.
12635  *
12636  * Sets an anchor point on the actor, based on the given gravity (this is a
12637  * convenience function wrapping clutter_actor_set_anchor_point()).
12638  *
12639  * Since version 1.0 the anchor point will be stored as a gravity so
12640  * that if the actor changes size then the anchor point will move. For
12641  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12642  * and later double the size of the actor, the anchor point will move
12643  * to the bottom right.
12644  *
12645  * Since: 0.6
12646  */
12647 void
12648 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12649                                              ClutterGravity  gravity)
12650 {
12651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12652
12653   if (gravity == CLUTTER_GRAVITY_NONE)
12654     clutter_actor_set_anchor_point (self, 0, 0);
12655   else
12656     {
12657       GObject *obj = G_OBJECT (self);
12658       ClutterTransformInfo *info;
12659
12660       g_object_freeze_notify (obj);
12661
12662       info = _clutter_actor_get_transform_info (self);
12663       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12664
12665       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12666       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12667       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12668
12669       self->priv->transform_valid = FALSE;
12670
12671       clutter_actor_queue_redraw (self);
12672
12673       g_object_thaw_notify (obj);
12674     }
12675 }
12676
12677 static void
12678 clutter_actor_store_content_box (ClutterActor *self,
12679                                  const ClutterActorBox *box)
12680 {
12681   if (box != NULL)
12682     {
12683       self->priv->content_box = *box;
12684       self->priv->content_box_valid = TRUE;
12685     }
12686   else
12687     self->priv->content_box_valid = FALSE;
12688
12689   clutter_actor_queue_redraw (self);
12690
12691   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12692 }
12693
12694 static void
12695 clutter_container_iface_init (ClutterContainerIface *iface)
12696 {
12697   /* we don't override anything, as ClutterContainer already has a default
12698    * implementation that we can use, and which calls into our own API.
12699    */
12700 }
12701
12702 typedef enum
12703 {
12704   PARSE_X,
12705   PARSE_Y,
12706   PARSE_WIDTH,
12707   PARSE_HEIGHT,
12708   PARSE_ANCHOR_X,
12709   PARSE_ANCHOR_Y
12710 } ParseDimension;
12711
12712 static gfloat
12713 parse_units (ClutterActor   *self,
12714              ParseDimension  dimension,
12715              JsonNode       *node)
12716 {
12717   GValue value = G_VALUE_INIT;
12718   gfloat retval = 0;
12719
12720   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12721     return 0;
12722
12723   json_node_get_value (node, &value);
12724
12725   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12726     {
12727       retval = (gfloat) g_value_get_int64 (&value);
12728     }
12729   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12730     {
12731       retval = g_value_get_double (&value);
12732     }
12733   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12734     {
12735       ClutterUnits units;
12736       gboolean res;
12737
12738       res = clutter_units_from_string (&units, g_value_get_string (&value));
12739       if (res)
12740         retval = clutter_units_to_pixels (&units);
12741       else
12742         {
12743           g_warning ("Invalid value '%s': integers, strings or floating point "
12744                      "values can be used for the x, y, width and height "
12745                      "properties. Valid modifiers for strings are 'px', 'mm', "
12746                      "'pt' and 'em'.",
12747                      g_value_get_string (&value));
12748           retval = 0;
12749         }
12750     }
12751   else
12752     {
12753       g_warning ("Invalid value of type '%s': integers, strings of floating "
12754                  "point values can be used for the x, y, width, height "
12755                  "anchor-x and anchor-y properties.",
12756                  g_type_name (G_VALUE_TYPE (&value)));
12757     }
12758
12759   g_value_unset (&value);
12760
12761   return retval;
12762 }
12763
12764 typedef struct {
12765   ClutterRotateAxis axis;
12766
12767   gdouble angle;
12768
12769   gfloat center_x;
12770   gfloat center_y;
12771   gfloat center_z;
12772 } RotationInfo;
12773
12774 static inline gboolean
12775 parse_rotation_array (ClutterActor *actor,
12776                       JsonArray    *array,
12777                       RotationInfo *info)
12778 {
12779   JsonNode *element;
12780
12781   if (json_array_get_length (array) != 2)
12782     return FALSE;
12783
12784   /* angle */
12785   element = json_array_get_element (array, 0);
12786   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12787     info->angle = json_node_get_double (element);
12788   else
12789     return FALSE;
12790
12791   /* center */
12792   element = json_array_get_element (array, 1);
12793   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12794     {
12795       JsonArray *center = json_node_get_array (element);
12796
12797       if (json_array_get_length (center) != 2)
12798         return FALSE;
12799
12800       switch (info->axis)
12801         {
12802         case CLUTTER_X_AXIS:
12803           info->center_y = parse_units (actor, PARSE_Y,
12804                                         json_array_get_element (center, 0));
12805           info->center_z = parse_units (actor, PARSE_Y,
12806                                         json_array_get_element (center, 1));
12807           return TRUE;
12808
12809         case CLUTTER_Y_AXIS:
12810           info->center_x = parse_units (actor, PARSE_X,
12811                                         json_array_get_element (center, 0));
12812           info->center_z = parse_units (actor, PARSE_X,
12813                                         json_array_get_element (center, 1));
12814           return TRUE;
12815
12816         case CLUTTER_Z_AXIS:
12817           info->center_x = parse_units (actor, PARSE_X,
12818                                         json_array_get_element (center, 0));
12819           info->center_y = parse_units (actor, PARSE_Y,
12820                                         json_array_get_element (center, 1));
12821           return TRUE;
12822         }
12823     }
12824
12825   return FALSE;
12826 }
12827
12828 static gboolean
12829 parse_rotation (ClutterActor *actor,
12830                 JsonNode     *node,
12831                 RotationInfo *info)
12832 {
12833   JsonArray *array;
12834   guint len, i;
12835   gboolean retval = FALSE;
12836
12837   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12838     {
12839       g_warning ("Invalid node of type '%s' found, expecting an array",
12840                  json_node_type_name (node));
12841       return FALSE;
12842     }
12843
12844   array = json_node_get_array (node);
12845   len = json_array_get_length (array);
12846
12847   for (i = 0; i < len; i++)
12848     {
12849       JsonNode *element = json_array_get_element (array, i);
12850       JsonObject *object;
12851       JsonNode *member;
12852
12853       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12854         {
12855           g_warning ("Invalid node of type '%s' found, expecting an object",
12856                      json_node_type_name (element));
12857           return FALSE;
12858         }
12859
12860       object = json_node_get_object (element);
12861
12862       if (json_object_has_member (object, "x-axis"))
12863         {
12864           member = json_object_get_member (object, "x-axis");
12865
12866           info->axis = CLUTTER_X_AXIS;
12867
12868           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12869             {
12870               info->angle = json_node_get_double (member);
12871               retval = TRUE;
12872             }
12873           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12874             retval = parse_rotation_array (actor,
12875                                            json_node_get_array (member),
12876                                            info);
12877           else
12878             retval = FALSE;
12879         }
12880       else if (json_object_has_member (object, "y-axis"))
12881         {
12882           member = json_object_get_member (object, "y-axis");
12883
12884           info->axis = CLUTTER_Y_AXIS;
12885
12886           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12887             {
12888               info->angle = json_node_get_double (member);
12889               retval = TRUE;
12890             }
12891           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12892             retval = parse_rotation_array (actor,
12893                                            json_node_get_array (member),
12894                                            info);
12895           else
12896             retval = FALSE;
12897         }
12898       else if (json_object_has_member (object, "z-axis"))
12899         {
12900           member = json_object_get_member (object, "z-axis");
12901
12902           info->axis = CLUTTER_Z_AXIS;
12903
12904           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12905             {
12906               info->angle = json_node_get_double (member);
12907               retval = TRUE;
12908             }
12909           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12910             retval = parse_rotation_array (actor,
12911                                            json_node_get_array (member),
12912                                            info);
12913           else
12914             retval = FALSE;
12915         }
12916     }
12917
12918   return retval;
12919 }
12920
12921 static GSList *
12922 parse_actor_metas (ClutterScript *script,
12923                    ClutterActor  *actor,
12924                    JsonNode      *node)
12925 {
12926   GList *elements, *l;
12927   GSList *retval = NULL;
12928
12929   if (!JSON_NODE_HOLDS_ARRAY (node))
12930     return NULL;
12931
12932   elements = json_array_get_elements (json_node_get_array (node));
12933
12934   for (l = elements; l != NULL; l = l->next)
12935     {
12936       JsonNode *element = l->data;
12937       const gchar *id_ = _clutter_script_get_id_from_node (element);
12938       GObject *meta;
12939
12940       if (id_ == NULL || *id_ == '\0')
12941         continue;
12942
12943       meta = clutter_script_get_object (script, id_);
12944       if (meta == NULL)
12945         continue;
12946
12947       retval = g_slist_prepend (retval, meta);
12948     }
12949
12950   g_list_free (elements);
12951
12952   return g_slist_reverse (retval);
12953 }
12954
12955 static GSList *
12956 parse_behaviours (ClutterScript *script,
12957                   ClutterActor  *actor,
12958                   JsonNode      *node)
12959 {
12960   GList *elements, *l;
12961   GSList *retval = NULL;
12962
12963   if (!JSON_NODE_HOLDS_ARRAY (node))
12964     return NULL;
12965
12966   elements = json_array_get_elements (json_node_get_array (node));
12967
12968   for (l = elements; l != NULL; l = l->next)
12969     {
12970       JsonNode *element = l->data;
12971       const gchar *id_ = _clutter_script_get_id_from_node (element);
12972       GObject *behaviour;
12973
12974       if (id_ == NULL || *id_ == '\0')
12975         continue;
12976
12977       behaviour = clutter_script_get_object (script, id_);
12978       if (behaviour == NULL)
12979         continue;
12980
12981       retval = g_slist_prepend (retval, behaviour);
12982     }
12983
12984   g_list_free (elements);
12985
12986   return g_slist_reverse (retval);
12987 }
12988
12989 static gboolean
12990 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12991                                  ClutterScript     *script,
12992                                  GValue            *value,
12993                                  const gchar       *name,
12994                                  JsonNode          *node)
12995 {
12996   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12997   gboolean retval = FALSE;
12998
12999   if ((name[0] == 'x' && name[1] == '\0') ||
13000       (name[0] == 'y' && name[1] == '\0') ||
13001       (strcmp (name, "width") == 0) ||
13002       (strcmp (name, "height") == 0) ||
13003       (strcmp (name, "anchor_x") == 0) ||
13004       (strcmp (name, "anchor_y") == 0))
13005     {
13006       ParseDimension dimension;
13007       gfloat units;
13008
13009       if (name[0] == 'x')
13010         dimension = PARSE_X;
13011       else if (name[0] == 'y')
13012         dimension = PARSE_Y;
13013       else if (name[0] == 'w')
13014         dimension = PARSE_WIDTH;
13015       else if (name[0] == 'h')
13016         dimension = PARSE_HEIGHT;
13017       else if (name[0] == 'a' && name[7] == 'x')
13018         dimension = PARSE_ANCHOR_X;
13019       else if (name[0] == 'a' && name[7] == 'y')
13020         dimension = PARSE_ANCHOR_Y;
13021       else
13022         return FALSE;
13023
13024       units = parse_units (actor, dimension, node);
13025
13026       /* convert back to pixels: all properties are pixel-based */
13027       g_value_init (value, G_TYPE_FLOAT);
13028       g_value_set_float (value, units);
13029
13030       retval = TRUE;
13031     }
13032   else if (strcmp (name, "rotation") == 0)
13033     {
13034       RotationInfo *info;
13035
13036       info = g_slice_new0 (RotationInfo);
13037       retval = parse_rotation (actor, node, info);
13038
13039       if (retval)
13040         {
13041           g_value_init (value, G_TYPE_POINTER);
13042           g_value_set_pointer (value, info);
13043         }
13044       else
13045         g_slice_free (RotationInfo, info);
13046     }
13047   else if (strcmp (name, "behaviours") == 0)
13048     {
13049       GSList *l;
13050
13051 #ifdef CLUTTER_ENABLE_DEBUG
13052       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13053         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13054                                      "and it should not be used in newly "
13055                                      "written ClutterScript definitions.");
13056 #endif
13057
13058       l = parse_behaviours (script, actor, node);
13059
13060       g_value_init (value, G_TYPE_POINTER);
13061       g_value_set_pointer (value, l);
13062
13063       retval = TRUE;
13064     }
13065   else if (strcmp (name, "actions") == 0 ||
13066            strcmp (name, "constraints") == 0 ||
13067            strcmp (name, "effects") == 0)
13068     {
13069       GSList *l;
13070
13071       l = parse_actor_metas (script, actor, node);
13072
13073       g_value_init (value, G_TYPE_POINTER);
13074       g_value_set_pointer (value, l);
13075
13076       retval = TRUE;
13077     }
13078
13079   return retval;
13080 }
13081
13082 static void
13083 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13084                                    ClutterScript     *script,
13085                                    const gchar       *name,
13086                                    const GValue      *value)
13087 {
13088   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13089
13090 #ifdef CLUTTER_ENABLE_DEBUG
13091   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13092     {
13093       gchar *tmp = g_strdup_value_contents (value);
13094
13095       CLUTTER_NOTE (SCRIPT,
13096                     "in ClutterActor::set_custom_property('%s') = %s",
13097                     name,
13098                     tmp);
13099
13100       g_free (tmp);
13101     }
13102 #endif /* CLUTTER_ENABLE_DEBUG */
13103
13104   if (strcmp (name, "rotation") == 0)
13105     {
13106       RotationInfo *info;
13107
13108       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13109         return;
13110
13111       info = g_value_get_pointer (value);
13112
13113       clutter_actor_set_rotation (actor,
13114                                   info->axis, info->angle,
13115                                   info->center_x,
13116                                   info->center_y,
13117                                   info->center_z);
13118
13119       g_slice_free (RotationInfo, info);
13120
13121       return;
13122     }
13123
13124   if (strcmp (name, "behaviours") == 0)
13125     {
13126       GSList *behaviours, *l;
13127
13128       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13129         return;
13130
13131       behaviours = g_value_get_pointer (value);
13132       for (l = behaviours; l != NULL; l = l->next)
13133         {
13134           ClutterBehaviour *behaviour = l->data;
13135
13136           clutter_behaviour_apply (behaviour, actor);
13137         }
13138
13139       g_slist_free (behaviours);
13140
13141       return;
13142     }
13143
13144   if (strcmp (name, "actions") == 0 ||
13145       strcmp (name, "constraints") == 0 ||
13146       strcmp (name, "effects") == 0)
13147     {
13148       GSList *metas, *l;
13149
13150       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13151         return;
13152
13153       metas = g_value_get_pointer (value);
13154       for (l = metas; l != NULL; l = l->next)
13155         {
13156           if (name[0] == 'a')
13157             clutter_actor_add_action (actor, l->data);
13158
13159           if (name[0] == 'c')
13160             clutter_actor_add_constraint (actor, l->data);
13161
13162           if (name[0] == 'e')
13163             clutter_actor_add_effect (actor, l->data);
13164         }
13165
13166       g_slist_free (metas);
13167
13168       return;
13169     }
13170
13171   g_object_set_property (G_OBJECT (scriptable), name, value);
13172 }
13173
13174 static void
13175 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13176 {
13177   iface->parse_custom_node = clutter_actor_parse_custom_node;
13178   iface->set_custom_property = clutter_actor_set_custom_property;
13179 }
13180
13181 static ClutterActorMeta *
13182 get_meta_from_animation_property (ClutterActor  *actor,
13183                                   const gchar   *name,
13184                                   gchar        **name_p)
13185 {
13186   ClutterActorPrivate *priv = actor->priv;
13187   ClutterActorMeta *meta = NULL;
13188   gchar **tokens;
13189
13190   /* if this is not a special property, fall through */
13191   if (name[0] != '@')
13192     return NULL;
13193
13194   /* detect the properties named using the following spec:
13195    *
13196    *   @<section>.<meta-name>.<property-name>
13197    *
13198    * where <section> can be one of the following:
13199    *
13200    *   - actions
13201    *   - constraints
13202    *   - effects
13203    *
13204    * and <meta-name> is the name set on a specific ActorMeta
13205    */
13206
13207   tokens = g_strsplit (name + 1, ".", -1);
13208   if (tokens == NULL || g_strv_length (tokens) != 3)
13209     {
13210       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13211                     name + 1);
13212       g_strfreev (tokens);
13213       return NULL;
13214     }
13215
13216   if (strcmp (tokens[0], "actions") == 0)
13217     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13218
13219   if (strcmp (tokens[0], "constraints") == 0)
13220     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13221
13222   if (strcmp (tokens[0], "effects") == 0)
13223     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13224
13225   if (name_p != NULL)
13226     *name_p = g_strdup (tokens[2]);
13227
13228   CLUTTER_NOTE (ANIMATION,
13229                 "Looking for property '%s' of object '%s' in section '%s'",
13230                 tokens[2],
13231                 tokens[1],
13232                 tokens[0]);
13233
13234   g_strfreev (tokens);
13235
13236   return meta;
13237 }
13238
13239 static GParamSpec *
13240 clutter_actor_find_property (ClutterAnimatable *animatable,
13241                              const gchar       *property_name)
13242 {
13243   ClutterActorMeta *meta = NULL;
13244   GObjectClass *klass = NULL;
13245   GParamSpec *pspec = NULL;
13246   gchar *p_name = NULL;
13247
13248   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13249                                            property_name,
13250                                            &p_name);
13251
13252   if (meta != NULL)
13253     {
13254       klass = G_OBJECT_GET_CLASS (meta);
13255
13256       pspec = g_object_class_find_property (klass, p_name);
13257     }
13258   else
13259     {
13260       klass = G_OBJECT_GET_CLASS (animatable);
13261
13262       pspec = g_object_class_find_property (klass, property_name);
13263     }
13264
13265   g_free (p_name);
13266
13267   return pspec;
13268 }
13269
13270 static void
13271 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13272                                  const gchar       *property_name,
13273                                  GValue            *initial)
13274 {
13275   ClutterActorMeta *meta = NULL;
13276   gchar *p_name = NULL;
13277
13278   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13279                                            property_name,
13280                                            &p_name);
13281
13282   if (meta != NULL)
13283     g_object_get_property (G_OBJECT (meta), p_name, initial);
13284   else
13285     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13286
13287   g_free (p_name);
13288 }
13289
13290 /*
13291  * clutter_actor_set_animatable_property:
13292  * @actor: a #ClutterActor
13293  * @prop_id: the paramspec id
13294  * @value: the value to set
13295  * @pspec: the paramspec
13296  *
13297  * Sets values of animatable properties.
13298  *
13299  * This is a variant of clutter_actor_set_property() that gets called
13300  * by the #ClutterAnimatable implementation of #ClutterActor for the
13301  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13302  * #GParamSpec.
13303  *
13304  * Unlike the implementation of #GObjectClass.set_property(), this
13305  * function will not update the interval if a transition involving an
13306  * animatable property is in progress - this avoids cycles with the
13307  * transition API calling the public API.
13308  */
13309 static void
13310 clutter_actor_set_animatable_property (ClutterActor *actor,
13311                                        guint         prop_id,
13312                                        const GValue *value,
13313                                        GParamSpec   *pspec)
13314 {
13315   GObject *obj = G_OBJECT (actor);
13316
13317   g_object_freeze_notify (obj);
13318
13319   switch (prop_id)
13320     {
13321     case PROP_X:
13322       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13323       break;
13324
13325     case PROP_Y:
13326       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13327       break;
13328
13329     case PROP_POSITION:
13330       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13331       break;
13332
13333     case PROP_WIDTH:
13334       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13335       break;
13336
13337     case PROP_HEIGHT:
13338       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13339       break;
13340
13341     case PROP_SIZE:
13342       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13343       break;
13344
13345     case PROP_DEPTH:
13346       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13347       break;
13348
13349     case PROP_OPACITY:
13350       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13351       break;
13352
13353     case PROP_BACKGROUND_COLOR:
13354       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13355       break;
13356
13357     case PROP_SCALE_X:
13358       clutter_actor_set_scale_factor_internal (actor,
13359                                                g_value_get_double (value),
13360                                                pspec);
13361       break;
13362
13363     case PROP_SCALE_Y:
13364       clutter_actor_set_scale_factor_internal (actor,
13365                                                g_value_get_double (value),
13366                                                pspec);
13367       break;
13368
13369     case PROP_ROTATION_ANGLE_X:
13370       clutter_actor_set_rotation_angle_internal (actor,
13371                                                  CLUTTER_X_AXIS,
13372                                                  g_value_get_double (value));
13373       break;
13374
13375     case PROP_ROTATION_ANGLE_Y:
13376       clutter_actor_set_rotation_angle_internal (actor,
13377                                                  CLUTTER_Y_AXIS,
13378                                                  g_value_get_double (value));
13379       break;
13380
13381     case PROP_ROTATION_ANGLE_Z:
13382       clutter_actor_set_rotation_angle_internal (actor,
13383                                                  CLUTTER_Z_AXIS,
13384                                                  g_value_get_double (value));
13385       break;
13386
13387     case PROP_CONTENT_BOX:
13388       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13389       break;
13390
13391     default:
13392       g_object_set_property (obj, pspec->name, value);
13393       break;
13394     }
13395
13396   g_object_thaw_notify (obj);
13397 }
13398
13399 static void
13400 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13401                                const gchar       *property_name,
13402                                const GValue      *final)
13403 {
13404   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13405   ClutterActorMeta *meta = NULL;
13406   gchar *p_name = NULL;
13407
13408   meta = get_meta_from_animation_property (actor,
13409                                            property_name,
13410                                            &p_name);
13411   if (meta != NULL)
13412     g_object_set_property (G_OBJECT (meta), p_name, final);
13413   else
13414     {
13415       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13416       GParamSpec *pspec;
13417
13418       pspec = g_object_class_find_property (obj_class, property_name);
13419
13420       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13421         {
13422           /* XXX - I'm going to the special hell for this */
13423           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13424         }
13425       else
13426         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13427     }
13428
13429   g_free (p_name);
13430 }
13431
13432 static void
13433 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13434 {
13435   iface->find_property = clutter_actor_find_property;
13436   iface->get_initial_state = clutter_actor_get_initial_state;
13437   iface->set_final_state = clutter_actor_set_final_state;
13438 }
13439
13440 /**
13441  * clutter_actor_transform_stage_point:
13442  * @self: A #ClutterActor
13443  * @x: (in): x screen coordinate of the point to unproject
13444  * @y: (in): y screen coordinate of the point to unproject
13445  * @x_out: (out): return location for the unprojected x coordinance
13446  * @y_out: (out): return location for the unprojected y coordinance
13447  *
13448  * This function translates screen coordinates (@x, @y) to
13449  * coordinates relative to the actor. For example, it can be used to translate
13450  * screen events from global screen coordinates into actor-local coordinates.
13451  *
13452  * The conversion can fail, notably if the transform stack results in the
13453  * actor being projected on the screen as a mere line.
13454  *
13455  * The conversion should not be expected to be pixel-perfect due to the
13456  * nature of the operation. In general the error grows when the skewing
13457  * of the actor rectangle on screen increases.
13458  *
13459  * <note><para>This function can be computationally intensive.</para></note>
13460  *
13461  * <note><para>This function only works when the allocation is up-to-date,
13462  * i.e. inside of paint().</para></note>
13463  *
13464  * Return value: %TRUE if conversion was successful.
13465  *
13466  * Since: 0.6
13467  */
13468 gboolean
13469 clutter_actor_transform_stage_point (ClutterActor *self,
13470                                      gfloat        x,
13471                                      gfloat        y,
13472                                      gfloat       *x_out,
13473                                      gfloat       *y_out)
13474 {
13475   ClutterVertex v[4];
13476   float ST[3][3];
13477   float RQ[3][3];
13478   int du, dv, xi, yi;
13479   float px, py;
13480   float xf, yf, wf, det;
13481   ClutterActorPrivate *priv;
13482
13483   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13484
13485   priv = self->priv;
13486
13487   /* This implementation is based on the quad -> quad projection algorithm
13488    * described by Paul Heckbert in:
13489    *
13490    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13491    *
13492    * and the sample implementation at:
13493    *
13494    *   http://www.cs.cmu.edu/~ph/src/texfund/
13495    *
13496    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13497    * quad to rectangle only, which significantly simplifies things; the
13498    * function calls have been unrolled, and most of the math is done in fixed
13499    * point.
13500    */
13501
13502   clutter_actor_get_abs_allocation_vertices (self, v);
13503
13504   /* Keeping these as ints simplifies the multiplication (no significant
13505    * loss of precision here).
13506    */
13507   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13508   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13509
13510   if (!du || !dv)
13511     return FALSE;
13512
13513 #define UX2FP(x)        (x)
13514 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13515
13516   /* First, find mapping from unit uv square to xy quadrilateral; this
13517    * equivalent to the pmap_square_quad() functions in the sample
13518    * implementation, which we can simplify, since our target is always
13519    * a rectangle.
13520    */
13521   px = v[0].x - v[1].x + v[3].x - v[2].x;
13522   py = v[0].y - v[1].y + v[3].y - v[2].y;
13523
13524   if (!px && !py)
13525     {
13526       /* affine transform */
13527       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13528       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13529       RQ[2][0] = UX2FP (v[0].x);
13530       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13531       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13532       RQ[2][1] = UX2FP (v[0].y);
13533       RQ[0][2] = 0;
13534       RQ[1][2] = 0;
13535       RQ[2][2] = 1.0;
13536     }
13537   else
13538     {
13539       /* projective transform */
13540       double dx1, dx2, dy1, dy2, del;
13541
13542       dx1 = UX2FP (v[1].x - v[3].x);
13543       dx2 = UX2FP (v[2].x - v[3].x);
13544       dy1 = UX2FP (v[1].y - v[3].y);
13545       dy2 = UX2FP (v[2].y - v[3].y);
13546
13547       del = DET2FP (dx1, dx2, dy1, dy2);
13548       if (!del)
13549         return FALSE;
13550
13551       /*
13552        * The division here needs to be done in floating point for
13553        * precisions reasons.
13554        */
13555       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13556       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13557       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13558       RQ[2][2] = 1.0;
13559       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13560       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13561       RQ[2][0] = UX2FP (v[0].x);
13562       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13563       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13564       RQ[2][1] = UX2FP (v[0].y);
13565     }
13566
13567   /*
13568    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13569    * square. Since our rectangle is based at 0,0 we only need to scale.
13570    */
13571   RQ[0][0] /= du;
13572   RQ[1][0] /= dv;
13573   RQ[0][1] /= du;
13574   RQ[1][1] /= dv;
13575   RQ[0][2] /= du;
13576   RQ[1][2] /= dv;
13577
13578   /*
13579    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13580    * inverse of that.
13581    */
13582   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13583   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13584   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13585   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13586   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13587   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13588   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13589   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13590   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13591
13592   /*
13593    * Check the resulting matrix is OK.
13594    */
13595   det = (RQ[0][0] * ST[0][0])
13596       + (RQ[0][1] * ST[0][1])
13597       + (RQ[0][2] * ST[0][2]);
13598   if (!det)
13599     return FALSE;
13600
13601   /*
13602    * Now transform our point with the ST matrix; the notional w
13603    * coordinate is 1, hence the last part is simply added.
13604    */
13605   xi = (int) x;
13606   yi = (int) y;
13607
13608   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13609   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13610   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13611
13612   if (x_out)
13613     *x_out = xf / wf;
13614
13615   if (y_out)
13616     *y_out = yf / wf;
13617
13618 #undef UX2FP
13619 #undef DET2FP
13620
13621   return TRUE;
13622 }
13623
13624 /**
13625  * clutter_actor_is_rotated:
13626  * @self: a #ClutterActor
13627  *
13628  * Checks whether any rotation is applied to the actor.
13629  *
13630  * Return value: %TRUE if the actor is rotated.
13631  *
13632  * Since: 0.6
13633  */
13634 gboolean
13635 clutter_actor_is_rotated (ClutterActor *self)
13636 {
13637   const ClutterTransformInfo *info;
13638
13639   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13640
13641   info = _clutter_actor_get_transform_info_or_defaults (self);
13642
13643   if (info->rx_angle || info->ry_angle || info->rz_angle)
13644     return TRUE;
13645
13646   return FALSE;
13647 }
13648
13649 /**
13650  * clutter_actor_is_scaled:
13651  * @self: a #ClutterActor
13652  *
13653  * Checks whether the actor is scaled in either dimension.
13654  *
13655  * Return value: %TRUE if the actor is scaled.
13656  *
13657  * Since: 0.6
13658  */
13659 gboolean
13660 clutter_actor_is_scaled (ClutterActor *self)
13661 {
13662   const ClutterTransformInfo *info;
13663
13664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13665
13666   info = _clutter_actor_get_transform_info_or_defaults (self);
13667
13668   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13669     return TRUE;
13670
13671   return FALSE;
13672 }
13673
13674 ClutterActor *
13675 _clutter_actor_get_stage_internal (ClutterActor *actor)
13676 {
13677   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13678     actor = actor->priv->parent;
13679
13680   return actor;
13681 }
13682
13683 /**
13684  * clutter_actor_get_stage:
13685  * @actor: a #ClutterActor
13686  *
13687  * Retrieves the #ClutterStage where @actor is contained.
13688  *
13689  * Return value: (transfer none) (type Clutter.Stage): the stage
13690  *   containing the actor, or %NULL
13691  *
13692  * Since: 0.8
13693  */
13694 ClutterActor *
13695 clutter_actor_get_stage (ClutterActor *actor)
13696 {
13697   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13698
13699   return _clutter_actor_get_stage_internal (actor);
13700 }
13701
13702 /**
13703  * clutter_actor_allocate_available_size:
13704  * @self: a #ClutterActor
13705  * @x: the actor's X coordinate
13706  * @y: the actor's Y coordinate
13707  * @available_width: the maximum available width, or -1 to use the
13708  *   actor's natural width
13709  * @available_height: the maximum available height, or -1 to use the
13710  *   actor's natural height
13711  * @flags: flags controlling the allocation
13712  *
13713  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13714  * preferred size, but limiting it to the maximum available width
13715  * and height provided.
13716  *
13717  * This function will do the right thing when dealing with the
13718  * actor's request mode.
13719  *
13720  * The implementation of this function is equivalent to:
13721  *
13722  * |[
13723  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13724  *     {
13725  *       clutter_actor_get_preferred_width (self, available_height,
13726  *                                          &amp;min_width,
13727  *                                          &amp;natural_width);
13728  *       width = CLAMP (natural_width, min_width, available_width);
13729  *
13730  *       clutter_actor_get_preferred_height (self, width,
13731  *                                           &amp;min_height,
13732  *                                           &amp;natural_height);
13733  *       height = CLAMP (natural_height, min_height, available_height);
13734  *     }
13735  *   else
13736  *     {
13737  *       clutter_actor_get_preferred_height (self, available_width,
13738  *                                           &amp;min_height,
13739  *                                           &amp;natural_height);
13740  *       height = CLAMP (natural_height, min_height, available_height);
13741  *
13742  *       clutter_actor_get_preferred_width (self, height,
13743  *                                          &amp;min_width,
13744  *                                          &amp;natural_width);
13745  *       width = CLAMP (natural_width, min_width, available_width);
13746  *     }
13747  *
13748  *   box.x1 = x; box.y1 = y;
13749  *   box.x2 = box.x1 + available_width;
13750  *   box.y2 = box.y1 + available_height;
13751  *   clutter_actor_allocate (self, &amp;box, flags);
13752  * ]|
13753  *
13754  * This function can be used by fluid layout managers to allocate
13755  * an actor's preferred size without making it bigger than the area
13756  * available for the container.
13757  *
13758  * Since: 1.0
13759  */
13760 void
13761 clutter_actor_allocate_available_size (ClutterActor           *self,
13762                                        gfloat                  x,
13763                                        gfloat                  y,
13764                                        gfloat                  available_width,
13765                                        gfloat                  available_height,
13766                                        ClutterAllocationFlags  flags)
13767 {
13768   ClutterActorPrivate *priv;
13769   gfloat width, height;
13770   gfloat min_width, min_height;
13771   gfloat natural_width, natural_height;
13772   ClutterActorBox box;
13773
13774   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13775
13776   priv = self->priv;
13777
13778   width = height = 0.0;
13779
13780   switch (priv->request_mode)
13781     {
13782     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13783       clutter_actor_get_preferred_width (self, available_height,
13784                                          &min_width,
13785                                          &natural_width);
13786       width  = CLAMP (natural_width, min_width, available_width);
13787
13788       clutter_actor_get_preferred_height (self, width,
13789                                           &min_height,
13790                                           &natural_height);
13791       height = CLAMP (natural_height, min_height, available_height);
13792       break;
13793
13794     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13795       clutter_actor_get_preferred_height (self, available_width,
13796                                           &min_height,
13797                                           &natural_height);
13798       height = CLAMP (natural_height, min_height, available_height);
13799
13800       clutter_actor_get_preferred_width (self, height,
13801                                          &min_width,
13802                                          &natural_width);
13803       width  = CLAMP (natural_width, min_width, available_width);
13804       break;
13805     }
13806
13807
13808   box.x1 = x;
13809   box.y1 = y;
13810   box.x2 = box.x1 + width;
13811   box.y2 = box.y1 + height;
13812   clutter_actor_allocate (self, &box, flags);
13813 }
13814
13815 /**
13816  * clutter_actor_allocate_preferred_size:
13817  * @self: a #ClutterActor
13818  * @flags: flags controlling the allocation
13819  *
13820  * Allocates the natural size of @self.
13821  *
13822  * This function is a utility call for #ClutterActor implementations
13823  * that allocates the actor's preferred natural size. It can be used
13824  * by fixed layout managers (like #ClutterGroup or so called
13825  * 'composite actors') inside the ClutterActor::allocate
13826  * implementation to give each child exactly how much space it
13827  * requires.
13828  *
13829  * This function is not meant to be used by applications. It is also
13830  * not meant to be used outside the implementation of the
13831  * ClutterActor::allocate virtual function.
13832  *
13833  * Since: 0.8
13834  */
13835 void
13836 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13837                                        ClutterAllocationFlags  flags)
13838 {
13839   gfloat actor_x, actor_y;
13840   gfloat natural_width, natural_height;
13841   ClutterActorBox actor_box;
13842
13843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13844
13845   actor_x = clutter_actor_get_x (self);
13846   actor_y = clutter_actor_get_y (self);
13847
13848   clutter_actor_get_preferred_size (self,
13849                                     NULL, NULL,
13850                                     &natural_width,
13851                                     &natural_height);
13852
13853   actor_box.x1 = actor_x;
13854   actor_box.y1 = actor_y;
13855   actor_box.x2 = actor_box.x1 + natural_width;
13856   actor_box.y2 = actor_box.y1 + natural_height;
13857
13858   clutter_actor_allocate (self, &actor_box, flags);
13859 }
13860
13861 /**
13862  * clutter_actor_allocate_align_fill:
13863  * @self: a #ClutterActor
13864  * @box: a #ClutterActorBox, containing the available width and height
13865  * @x_align: the horizontal alignment, between 0 and 1
13866  * @y_align: the vertical alignment, between 0 and 1
13867  * @x_fill: whether the actor should fill horizontally
13868  * @y_fill: whether the actor should fill vertically
13869  * @flags: allocation flags to be passed to clutter_actor_allocate()
13870  *
13871  * Allocates @self by taking into consideration the available allocation
13872  * area; an alignment factor on either axis; and whether the actor should
13873  * fill the allocation on either axis.
13874  *
13875  * The @box should contain the available allocation width and height;
13876  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13877  * allocation will be offset by their value.
13878  *
13879  * This function takes into consideration the geometry request specified by
13880  * the #ClutterActor:request-mode property, and the text direction.
13881  *
13882  * This function is useful for fluid layout managers, like #ClutterBinLayout
13883  * or #ClutterTableLayout
13884  *
13885  * Since: 1.4
13886  */
13887 void
13888 clutter_actor_allocate_align_fill (ClutterActor           *self,
13889                                    const ClutterActorBox  *box,
13890                                    gdouble                 x_align,
13891                                    gdouble                 y_align,
13892                                    gboolean                x_fill,
13893                                    gboolean                y_fill,
13894                                    ClutterAllocationFlags  flags)
13895 {
13896   ClutterActorPrivate *priv;
13897   ClutterActorBox allocation = { 0, };
13898   gfloat x_offset, y_offset;
13899   gfloat available_width, available_height;
13900   gfloat child_width, child_height;
13901
13902   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13903   g_return_if_fail (box != NULL);
13904   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13905   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13906
13907   priv = self->priv;
13908
13909   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13910   clutter_actor_box_get_size (box, &available_width, &available_height);
13911
13912   if (available_width < 0)
13913     available_width = 0;
13914
13915   if (available_height < 0)
13916     available_height = 0;
13917
13918   if (x_fill)
13919     {
13920       allocation.x1 = x_offset;
13921       allocation.x2 = allocation.x1 + available_width;
13922     }
13923
13924   if (y_fill)
13925     {
13926       allocation.y1 = y_offset;
13927       allocation.y2 = allocation.y1 + available_height;
13928     }
13929
13930   /* if we are filling horizontally and vertically then we're done */
13931   if (x_fill && y_fill)
13932     goto out;
13933
13934   child_width = child_height = 0.0f;
13935
13936   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13937     {
13938       gfloat min_width, natural_width;
13939       gfloat min_height, natural_height;
13940
13941       clutter_actor_get_preferred_width (self, available_height,
13942                                          &min_width,
13943                                          &natural_width);
13944
13945       child_width = CLAMP (natural_width, min_width, available_width);
13946
13947       if (!y_fill)
13948         {
13949           clutter_actor_get_preferred_height (self, child_width,
13950                                               &min_height,
13951                                               &natural_height);
13952
13953           child_height = CLAMP (natural_height, min_height, available_height);
13954         }
13955     }
13956   else
13957     {
13958       gfloat min_width, natural_width;
13959       gfloat min_height, natural_height;
13960
13961       clutter_actor_get_preferred_height (self, available_width,
13962                                           &min_height,
13963                                           &natural_height);
13964
13965       child_height = CLAMP (natural_height, min_height, available_height);
13966
13967       if (!x_fill)
13968         {
13969           clutter_actor_get_preferred_width (self, child_height,
13970                                              &min_width,
13971                                              &natural_width);
13972
13973           child_width = CLAMP (natural_width, min_width, available_width);
13974         }
13975     }
13976
13977   /* invert the horizontal alignment for RTL languages */
13978   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13979     x_align = 1.0 - x_align;
13980
13981   if (!x_fill)
13982     {
13983       allocation.x1 = x_offset
13984                     + ((available_width - child_width) * x_align);
13985       allocation.x2 = allocation.x1 + child_width;
13986     }
13987
13988   if (!y_fill)
13989     {
13990       allocation.y1 = y_offset
13991                     + ((available_height - child_height) * y_align);
13992       allocation.y2 = allocation.y1 + child_height;
13993     }
13994
13995 out:
13996   clutter_actor_box_clamp_to_pixel (&allocation);
13997   clutter_actor_allocate (self, &allocation, flags);
13998 }
13999
14000 /**
14001  * clutter_actor_grab_key_focus:
14002  * @self: a #ClutterActor
14003  *
14004  * Sets the key focus of the #ClutterStage including @self
14005  * to this #ClutterActor.
14006  *
14007  * Since: 1.0
14008  */
14009 void
14010 clutter_actor_grab_key_focus (ClutterActor *self)
14011 {
14012   ClutterActor *stage;
14013
14014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14015
14016   stage = _clutter_actor_get_stage_internal (self);
14017   if (stage != NULL)
14018     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14019 }
14020
14021 /**
14022  * clutter_actor_get_pango_context:
14023  * @self: a #ClutterActor
14024  *
14025  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14026  * is already configured using the appropriate font map, resolution
14027  * and font options.
14028  *
14029  * Unlike clutter_actor_create_pango_context(), this context is owend
14030  * by the #ClutterActor and it will be updated each time the options
14031  * stored by the #ClutterBackend change.
14032  *
14033  * You can use the returned #PangoContext to create a #PangoLayout
14034  * and render text using cogl_pango_render_layout() to reuse the
14035  * glyphs cache also used by Clutter.
14036  *
14037  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14038  *   The returned #PangoContext is owned by the actor and should not be
14039  *   unreferenced by the application code
14040  *
14041  * Since: 1.0
14042  */
14043 PangoContext *
14044 clutter_actor_get_pango_context (ClutterActor *self)
14045 {
14046   ClutterActorPrivate *priv;
14047
14048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14049
14050   priv = self->priv;
14051
14052   if (priv->pango_context != NULL)
14053     return priv->pango_context;
14054
14055   priv->pango_context = _clutter_context_get_pango_context ();
14056   g_object_ref (priv->pango_context);
14057
14058   return priv->pango_context;
14059 }
14060
14061 /**
14062  * clutter_actor_create_pango_context:
14063  * @self: a #ClutterActor
14064  *
14065  * Creates a #PangoContext for the given actor. The #PangoContext
14066  * is already configured using the appropriate font map, resolution
14067  * and font options.
14068  *
14069  * See also clutter_actor_get_pango_context().
14070  *
14071  * Return value: (transfer full): the newly created #PangoContext.
14072  *   Use g_object_unref() on the returned value to deallocate its
14073  *   resources
14074  *
14075  * Since: 1.0
14076  */
14077 PangoContext *
14078 clutter_actor_create_pango_context (ClutterActor *self)
14079 {
14080   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14081
14082   return _clutter_context_create_pango_context ();
14083 }
14084
14085 /**
14086  * clutter_actor_create_pango_layout:
14087  * @self: a #ClutterActor
14088  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14089  *
14090  * Creates a new #PangoLayout from the same #PangoContext used
14091  * by the #ClutterActor. The #PangoLayout is already configured
14092  * with the font map, resolution and font options, and the
14093  * given @text.
14094  *
14095  * If you want to keep around a #PangoLayout created by this
14096  * function you will have to connect to the #ClutterBackend::font-changed
14097  * and #ClutterBackend::resolution-changed signals, and call
14098  * pango_layout_context_changed() in response to them.
14099  *
14100  * Return value: (transfer full): the newly created #PangoLayout.
14101  *   Use g_object_unref() when done
14102  *
14103  * Since: 1.0
14104  */
14105 PangoLayout *
14106 clutter_actor_create_pango_layout (ClutterActor *self,
14107                                    const gchar  *text)
14108 {
14109   PangoContext *context;
14110   PangoLayout *layout;
14111
14112   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14113
14114   context = clutter_actor_get_pango_context (self);
14115   layout = pango_layout_new (context);
14116
14117   if (text)
14118     pango_layout_set_text (layout, text, -1);
14119
14120   return layout;
14121 }
14122
14123 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14124  * ClutterOffscreenEffect.
14125  */
14126 void
14127 _clutter_actor_set_opacity_override (ClutterActor *self,
14128                                      gint          opacity)
14129 {
14130   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14131
14132   self->priv->opacity_override = opacity;
14133 }
14134
14135 gint
14136 _clutter_actor_get_opacity_override (ClutterActor *self)
14137 {
14138   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14139
14140   return self->priv->opacity_override;
14141 }
14142
14143 /* Allows you to disable applying the actors model view transform during
14144  * a paint. Used by ClutterClone. */
14145 void
14146 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14147                                                 gboolean      enable)
14148 {
14149   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14150
14151   self->priv->enable_model_view_transform = enable;
14152 }
14153
14154 void
14155 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14156                                           gboolean      enable)
14157 {
14158   ClutterActorPrivate *priv;
14159
14160   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14161
14162   priv = self->priv;
14163
14164   priv->enable_paint_unmapped = enable;
14165
14166   if (priv->enable_paint_unmapped)
14167     {
14168       /* Make sure that the parents of the widget are realized first;
14169        * otherwise checks in clutter_actor_update_map_state() will
14170        * fail.
14171        */
14172       clutter_actor_realize (self);
14173
14174       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14175     }
14176   else
14177     {
14178       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14179     }
14180 }
14181
14182 static void
14183 clutter_anchor_coord_get_units (ClutterActor      *self,
14184                                 const AnchorCoord *coord,
14185                                 gfloat            *x,
14186                                 gfloat            *y,
14187                                 gfloat            *z)
14188 {
14189   if (coord->is_fractional)
14190     {
14191       gfloat actor_width, actor_height;
14192
14193       clutter_actor_get_size (self, &actor_width, &actor_height);
14194
14195       if (x)
14196         *x = actor_width * coord->v.fraction.x;
14197
14198       if (y)
14199         *y = actor_height * coord->v.fraction.y;
14200
14201       if (z)
14202         *z = 0;
14203     }
14204   else
14205     {
14206       if (x)
14207         *x = coord->v.units.x;
14208
14209       if (y)
14210         *y = coord->v.units.y;
14211
14212       if (z)
14213         *z = coord->v.units.z;
14214     }
14215 }
14216
14217 static void
14218 clutter_anchor_coord_set_units (AnchorCoord *coord,
14219                                 gfloat       x,
14220                                 gfloat       y,
14221                                 gfloat       z)
14222 {
14223   coord->is_fractional = FALSE;
14224   coord->v.units.x = x;
14225   coord->v.units.y = y;
14226   coord->v.units.z = z;
14227 }
14228
14229 static ClutterGravity
14230 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14231 {
14232   if (coord->is_fractional)
14233     {
14234       if (coord->v.fraction.x == 0.0)
14235         {
14236           if (coord->v.fraction.y == 0.0)
14237             return CLUTTER_GRAVITY_NORTH_WEST;
14238           else if (coord->v.fraction.y == 0.5)
14239             return CLUTTER_GRAVITY_WEST;
14240           else if (coord->v.fraction.y == 1.0)
14241             return CLUTTER_GRAVITY_SOUTH_WEST;
14242           else
14243             return CLUTTER_GRAVITY_NONE;
14244         }
14245       else if (coord->v.fraction.x == 0.5)
14246         {
14247           if (coord->v.fraction.y == 0.0)
14248             return CLUTTER_GRAVITY_NORTH;
14249           else if (coord->v.fraction.y == 0.5)
14250             return CLUTTER_GRAVITY_CENTER;
14251           else if (coord->v.fraction.y == 1.0)
14252             return CLUTTER_GRAVITY_SOUTH;
14253           else
14254             return CLUTTER_GRAVITY_NONE;
14255         }
14256       else if (coord->v.fraction.x == 1.0)
14257         {
14258           if (coord->v.fraction.y == 0.0)
14259             return CLUTTER_GRAVITY_NORTH_EAST;
14260           else if (coord->v.fraction.y == 0.5)
14261             return CLUTTER_GRAVITY_EAST;
14262           else if (coord->v.fraction.y == 1.0)
14263             return CLUTTER_GRAVITY_SOUTH_EAST;
14264           else
14265             return CLUTTER_GRAVITY_NONE;
14266         }
14267       else
14268         return CLUTTER_GRAVITY_NONE;
14269     }
14270   else
14271     return CLUTTER_GRAVITY_NONE;
14272 }
14273
14274 static void
14275 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14276                                   ClutterGravity  gravity)
14277 {
14278   switch (gravity)
14279     {
14280     case CLUTTER_GRAVITY_NORTH:
14281       coord->v.fraction.x = 0.5;
14282       coord->v.fraction.y = 0.0;
14283       break;
14284
14285     case CLUTTER_GRAVITY_NORTH_EAST:
14286       coord->v.fraction.x = 1.0;
14287       coord->v.fraction.y = 0.0;
14288       break;
14289
14290     case CLUTTER_GRAVITY_EAST:
14291       coord->v.fraction.x = 1.0;
14292       coord->v.fraction.y = 0.5;
14293       break;
14294
14295     case CLUTTER_GRAVITY_SOUTH_EAST:
14296       coord->v.fraction.x = 1.0;
14297       coord->v.fraction.y = 1.0;
14298       break;
14299
14300     case CLUTTER_GRAVITY_SOUTH:
14301       coord->v.fraction.x = 0.5;
14302       coord->v.fraction.y = 1.0;
14303       break;
14304
14305     case CLUTTER_GRAVITY_SOUTH_WEST:
14306       coord->v.fraction.x = 0.0;
14307       coord->v.fraction.y = 1.0;
14308       break;
14309
14310     case CLUTTER_GRAVITY_WEST:
14311       coord->v.fraction.x = 0.0;
14312       coord->v.fraction.y = 0.5;
14313       break;
14314
14315     case CLUTTER_GRAVITY_NORTH_WEST:
14316       coord->v.fraction.x = 0.0;
14317       coord->v.fraction.y = 0.0;
14318       break;
14319
14320     case CLUTTER_GRAVITY_CENTER:
14321       coord->v.fraction.x = 0.5;
14322       coord->v.fraction.y = 0.5;
14323       break;
14324
14325     default:
14326       coord->v.fraction.x = 0.0;
14327       coord->v.fraction.y = 0.0;
14328       break;
14329     }
14330
14331   coord->is_fractional = TRUE;
14332 }
14333
14334 static gboolean
14335 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14336 {
14337   if (coord->is_fractional)
14338     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14339   else
14340     return (coord->v.units.x == 0.0
14341             && coord->v.units.y == 0.0
14342             && coord->v.units.z == 0.0);
14343 }
14344
14345 /**
14346  * clutter_actor_get_flags:
14347  * @self: a #ClutterActor
14348  *
14349  * Retrieves the flags set on @self
14350  *
14351  * Return value: a bitwise or of #ClutterActorFlags or 0
14352  *
14353  * Since: 1.0
14354  */
14355 ClutterActorFlags
14356 clutter_actor_get_flags (ClutterActor *self)
14357 {
14358   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14359
14360   return self->flags;
14361 }
14362
14363 /**
14364  * clutter_actor_set_flags:
14365  * @self: a #ClutterActor
14366  * @flags: the flags to set
14367  *
14368  * Sets @flags on @self
14369  *
14370  * This function will emit notifications for the changed properties
14371  *
14372  * Since: 1.0
14373  */
14374 void
14375 clutter_actor_set_flags (ClutterActor      *self,
14376                          ClutterActorFlags  flags)
14377 {
14378   ClutterActorFlags old_flags;
14379   GObject *obj;
14380   gboolean was_reactive_set, reactive_set;
14381   gboolean was_realized_set, realized_set;
14382   gboolean was_mapped_set, mapped_set;
14383   gboolean was_visible_set, visible_set;
14384
14385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14386
14387   if (self->flags == flags)
14388     return;
14389
14390   obj = G_OBJECT (self);
14391   g_object_ref (obj);
14392   g_object_freeze_notify (obj);
14393
14394   old_flags = self->flags;
14395
14396   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14397   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14398   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14399   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14400
14401   self->flags |= flags;
14402
14403   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14404   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14405   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14406   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14407
14408   if (reactive_set != was_reactive_set)
14409     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14410
14411   if (realized_set != was_realized_set)
14412     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14413
14414   if (mapped_set != was_mapped_set)
14415     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14416
14417   if (visible_set != was_visible_set)
14418     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14419
14420   g_object_thaw_notify (obj);
14421   g_object_unref (obj);
14422 }
14423
14424 /**
14425  * clutter_actor_unset_flags:
14426  * @self: a #ClutterActor
14427  * @flags: the flags to unset
14428  *
14429  * Unsets @flags on @self
14430  *
14431  * This function will emit notifications for the changed properties
14432  *
14433  * Since: 1.0
14434  */
14435 void
14436 clutter_actor_unset_flags (ClutterActor      *self,
14437                            ClutterActorFlags  flags)
14438 {
14439   ClutterActorFlags old_flags;
14440   GObject *obj;
14441   gboolean was_reactive_set, reactive_set;
14442   gboolean was_realized_set, realized_set;
14443   gboolean was_mapped_set, mapped_set;
14444   gboolean was_visible_set, visible_set;
14445
14446   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14447
14448   obj = G_OBJECT (self);
14449   g_object_freeze_notify (obj);
14450
14451   old_flags = self->flags;
14452
14453   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14454   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14455   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14456   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14457
14458   self->flags &= ~flags;
14459
14460   if (self->flags == old_flags)
14461     return;
14462
14463   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14464   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14465   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14466   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14467
14468   if (reactive_set != was_reactive_set)
14469     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14470
14471   if (realized_set != was_realized_set)
14472     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14473
14474   if (mapped_set != was_mapped_set)
14475     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14476
14477   if (visible_set != was_visible_set)
14478     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14479
14480   g_object_thaw_notify (obj);
14481 }
14482
14483 /**
14484  * clutter_actor_get_transformation_matrix:
14485  * @self: a #ClutterActor
14486  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14487  *
14488  * Retrieves the transformations applied to @self relative to its
14489  * parent.
14490  *
14491  * Since: 1.0
14492  */
14493 void
14494 clutter_actor_get_transformation_matrix (ClutterActor *self,
14495                                          CoglMatrix   *matrix)
14496 {
14497   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14498
14499   cogl_matrix_init_identity (matrix);
14500
14501   _clutter_actor_apply_modelview_transform (self, matrix);
14502 }
14503
14504 void
14505 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14506                                    gboolean      is_in_clone_paint)
14507 {
14508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14509   self->priv->in_clone_paint = is_in_clone_paint;
14510 }
14511
14512 /**
14513  * clutter_actor_is_in_clone_paint:
14514  * @self: a #ClutterActor
14515  *
14516  * Checks whether @self is being currently painted by a #ClutterClone
14517  *
14518  * This function is useful only inside the ::paint virtual function
14519  * implementations or within handlers for the #ClutterActor::paint
14520  * signal
14521  *
14522  * This function should not be used by applications
14523  *
14524  * Return value: %TRUE if the #ClutterActor is currently being painted
14525  *   by a #ClutterClone, and %FALSE otherwise
14526  *
14527  * Since: 1.0
14528  */
14529 gboolean
14530 clutter_actor_is_in_clone_paint (ClutterActor *self)
14531 {
14532   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14533
14534   return self->priv->in_clone_paint;
14535 }
14536
14537 static gboolean
14538 set_direction_recursive (ClutterActor *actor,
14539                          gpointer      user_data)
14540 {
14541   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14542
14543   clutter_actor_set_text_direction (actor, text_dir);
14544
14545   return TRUE;
14546 }
14547
14548 /**
14549  * clutter_actor_set_text_direction:
14550  * @self: a #ClutterActor
14551  * @text_dir: the text direction for @self
14552  *
14553  * Sets the #ClutterTextDirection for an actor
14554  *
14555  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14556  *
14557  * If @self implements #ClutterContainer then this function will recurse
14558  * inside all the children of @self (including the internal ones).
14559  *
14560  * Composite actors not implementing #ClutterContainer, or actors requiring
14561  * special handling when the text direction changes, should connect to
14562  * the #GObject::notify signal for the #ClutterActor:text-direction property
14563  *
14564  * Since: 1.2
14565  */
14566 void
14567 clutter_actor_set_text_direction (ClutterActor         *self,
14568                                   ClutterTextDirection  text_dir)
14569 {
14570   ClutterActorPrivate *priv;
14571
14572   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14573   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14574
14575   priv = self->priv;
14576
14577   if (priv->text_direction != text_dir)
14578     {
14579       priv->text_direction = text_dir;
14580
14581       /* we need to emit the notify::text-direction first, so that
14582        * the sub-classes can catch that and do specific handling of
14583        * the text direction; see clutter_text_direction_changed_cb()
14584        * inside clutter-text.c
14585        */
14586       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14587
14588       _clutter_actor_foreach_child (self, set_direction_recursive,
14589                                     GINT_TO_POINTER (text_dir));
14590
14591       clutter_actor_queue_relayout (self);
14592     }
14593 }
14594
14595 void
14596 _clutter_actor_set_has_pointer (ClutterActor *self,
14597                                 gboolean      has_pointer)
14598 {
14599   ClutterActorPrivate *priv = self->priv;
14600
14601   if (priv->has_pointer != has_pointer)
14602     {
14603       priv->has_pointer = has_pointer;
14604
14605       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14606     }
14607 }
14608
14609 /**
14610  * clutter_actor_get_text_direction:
14611  * @self: a #ClutterActor
14612  *
14613  * Retrieves the value set using clutter_actor_set_text_direction()
14614  *
14615  * If no text direction has been previously set, the default text
14616  * direction, as returned by clutter_get_default_text_direction(), will
14617  * be returned instead
14618  *
14619  * Return value: the #ClutterTextDirection for the actor
14620  *
14621  * Since: 1.2
14622  */
14623 ClutterTextDirection
14624 clutter_actor_get_text_direction (ClutterActor *self)
14625 {
14626   ClutterActorPrivate *priv;
14627
14628   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14629                         CLUTTER_TEXT_DIRECTION_LTR);
14630
14631   priv = self->priv;
14632
14633   /* if no direction has been set yet use the default */
14634   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14635     priv->text_direction = clutter_get_default_text_direction ();
14636
14637   return priv->text_direction;
14638 }
14639
14640 /**
14641  * clutter_actor_push_internal:
14642  * @self: a #ClutterActor
14643  *
14644  * Should be used by actors implementing the #ClutterContainer and with
14645  * internal children added through clutter_actor_set_parent(), for instance:
14646  *
14647  * |[
14648  *   static void
14649  *   my_actor_init (MyActor *self)
14650  *   {
14651  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14652  *
14653  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14654  *
14655  *     /&ast; calling clutter_actor_set_parent() now will result in
14656  *      &ast; the internal flag being set on a child of MyActor
14657  *      &ast;/
14658  *
14659  *     /&ast; internal child - a background texture &ast;/
14660  *     self->priv->background_tex = clutter_texture_new ();
14661  *     clutter_actor_set_parent (self->priv->background_tex,
14662  *                               CLUTTER_ACTOR (self));
14663  *
14664  *     /&ast; internal child - a label &ast;/
14665  *     self->priv->label = clutter_text_new ();
14666  *     clutter_actor_set_parent (self->priv->label,
14667  *                               CLUTTER_ACTOR (self));
14668  *
14669  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14670  *
14671  *     /&ast; calling clutter_actor_set_parent() now will not result in
14672  *      &ast; the internal flag being set on a child of MyActor
14673  *      &ast;/
14674  *   }
14675  * ]|
14676  *
14677  * This function will be used by Clutter to toggle an "internal child"
14678  * flag whenever clutter_actor_set_parent() is called; internal children
14679  * are handled differently by Clutter, specifically when destroying their
14680  * parent.
14681  *
14682  * Call clutter_actor_pop_internal() when you finished adding internal
14683  * children.
14684  *
14685  * Nested calls to clutter_actor_push_internal() are allowed, but each
14686  * one must by followed by a clutter_actor_pop_internal() call.
14687  *
14688  * Since: 1.2
14689  *
14690  * Deprecated: 1.10: All children of an actor are accessible through
14691  *   the #ClutterActor API, and #ClutterActor implements the
14692  *   #ClutterContainer interface, so this function is only useful
14693  *   for legacy containers overriding the default implementation.
14694  */
14695 void
14696 clutter_actor_push_internal (ClutterActor *self)
14697 {
14698   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14699
14700   self->priv->internal_child += 1;
14701 }
14702
14703 /**
14704  * clutter_actor_pop_internal:
14705  * @self: a #ClutterActor
14706  *
14707  * Disables the effects of clutter_actor_push_internal().
14708  *
14709  * Since: 1.2
14710  *
14711  * Deprecated: 1.10: All children of an actor are accessible through
14712  *   the #ClutterActor API. This function is only useful for legacy
14713  *   containers overriding the default implementation of the
14714  *   #ClutterContainer interface.
14715  */
14716 void
14717 clutter_actor_pop_internal (ClutterActor *self)
14718 {
14719   ClutterActorPrivate *priv;
14720
14721   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14722
14723   priv = self->priv;
14724
14725   if (priv->internal_child == 0)
14726     {
14727       g_warning ("Mismatched %s: you need to call "
14728                  "clutter_actor_push_composite() at least once before "
14729                  "calling this function", G_STRFUNC);
14730       return;
14731     }
14732
14733   priv->internal_child -= 1;
14734 }
14735
14736 /**
14737  * clutter_actor_has_pointer:
14738  * @self: a #ClutterActor
14739  *
14740  * Checks whether an actor contains the pointer of a
14741  * #ClutterInputDevice
14742  *
14743  * Return value: %TRUE if the actor contains the pointer, and
14744  *   %FALSE otherwise
14745  *
14746  * Since: 1.2
14747  */
14748 gboolean
14749 clutter_actor_has_pointer (ClutterActor *self)
14750 {
14751   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14752
14753   return self->priv->has_pointer;
14754 }
14755
14756 /* XXX: This is a workaround for not being able to break the ABI of
14757  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14758  * clutter_actor_queue_clipped_redraw() for details.
14759  */
14760 ClutterPaintVolume *
14761 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14762 {
14763   return g_object_get_data (G_OBJECT (self),
14764                             "-clutter-actor-queue-redraw-clip");
14765 }
14766
14767 void
14768 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14769                                       ClutterPaintVolume *clip)
14770 {
14771   g_object_set_data (G_OBJECT (self),
14772                      "-clutter-actor-queue-redraw-clip",
14773                      clip);
14774 }
14775
14776 /**
14777  * clutter_actor_has_allocation:
14778  * @self: a #ClutterActor
14779  *
14780  * Checks if the actor has an up-to-date allocation assigned to
14781  * it. This means that the actor should have an allocation: it's
14782  * visible and has a parent. It also means that there is no
14783  * outstanding relayout request in progress for the actor or its
14784  * children (There might be other outstanding layout requests in
14785  * progress that will cause the actor to get a new allocation
14786  * when the stage is laid out, however).
14787  *
14788  * If this function returns %FALSE, then the actor will normally
14789  * be allocated before it is next drawn on the screen.
14790  *
14791  * Return value: %TRUE if the actor has an up-to-date allocation
14792  *
14793  * Since: 1.4
14794  */
14795 gboolean
14796 clutter_actor_has_allocation (ClutterActor *self)
14797 {
14798   ClutterActorPrivate *priv;
14799
14800   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14801
14802   priv = self->priv;
14803
14804   return priv->parent != NULL &&
14805          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14806          !priv->needs_allocation;
14807 }
14808
14809 /**
14810  * clutter_actor_add_action:
14811  * @self: a #ClutterActor
14812  * @action: a #ClutterAction
14813  *
14814  * Adds @action to the list of actions applied to @self
14815  *
14816  * A #ClutterAction can only belong to one actor at a time
14817  *
14818  * The #ClutterActor will hold a reference on @action until either
14819  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14820  * is called
14821  *
14822  * Since: 1.4
14823  */
14824 void
14825 clutter_actor_add_action (ClutterActor  *self,
14826                           ClutterAction *action)
14827 {
14828   ClutterActorPrivate *priv;
14829
14830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14831   g_return_if_fail (CLUTTER_IS_ACTION (action));
14832
14833   priv = self->priv;
14834
14835   if (priv->actions == NULL)
14836     {
14837       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14838       priv->actions->actor = self;
14839     }
14840
14841   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14842
14843   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14844 }
14845
14846 /**
14847  * clutter_actor_add_action_with_name:
14848  * @self: a #ClutterActor
14849  * @name: the name to set on the action
14850  * @action: a #ClutterAction
14851  *
14852  * A convenience function for setting the name of a #ClutterAction
14853  * while adding it to the list of actions applied to @self
14854  *
14855  * This function is the logical equivalent of:
14856  *
14857  * |[
14858  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14859  *   clutter_actor_add_action (self, action);
14860  * ]|
14861  *
14862  * Since: 1.4
14863  */
14864 void
14865 clutter_actor_add_action_with_name (ClutterActor  *self,
14866                                     const gchar   *name,
14867                                     ClutterAction *action)
14868 {
14869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14870   g_return_if_fail (name != NULL);
14871   g_return_if_fail (CLUTTER_IS_ACTION (action));
14872
14873   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14874   clutter_actor_add_action (self, action);
14875 }
14876
14877 /**
14878  * clutter_actor_remove_action:
14879  * @self: a #ClutterActor
14880  * @action: a #ClutterAction
14881  *
14882  * Removes @action from the list of actions applied to @self
14883  *
14884  * The reference held by @self on the #ClutterAction will be released
14885  *
14886  * Since: 1.4
14887  */
14888 void
14889 clutter_actor_remove_action (ClutterActor  *self,
14890                              ClutterAction *action)
14891 {
14892   ClutterActorPrivate *priv;
14893
14894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895   g_return_if_fail (CLUTTER_IS_ACTION (action));
14896
14897   priv = self->priv;
14898
14899   if (priv->actions == NULL)
14900     return;
14901
14902   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14903
14904   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14905     g_clear_object (&priv->actions);
14906
14907   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14908 }
14909
14910 /**
14911  * clutter_actor_remove_action_by_name:
14912  * @self: a #ClutterActor
14913  * @name: the name of the action to remove
14914  *
14915  * Removes the #ClutterAction with the given name from the list
14916  * of actions applied to @self
14917  *
14918  * Since: 1.4
14919  */
14920 void
14921 clutter_actor_remove_action_by_name (ClutterActor *self,
14922                                      const gchar  *name)
14923 {
14924   ClutterActorPrivate *priv;
14925   ClutterActorMeta *meta;
14926
14927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14928   g_return_if_fail (name != NULL);
14929
14930   priv = self->priv;
14931
14932   if (priv->actions == NULL)
14933     return;
14934
14935   meta = _clutter_meta_group_get_meta (priv->actions, name);
14936   if (meta == NULL)
14937     return;
14938
14939   _clutter_meta_group_remove_meta (priv->actions, meta);
14940
14941   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14942 }
14943
14944 /**
14945  * clutter_actor_get_actions:
14946  * @self: a #ClutterActor
14947  *
14948  * Retrieves the list of actions applied to @self
14949  *
14950  * Return value: (transfer container) (element-type Clutter.Action): a copy
14951  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14952  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14953  *   allocated by the returned #GList
14954  *
14955  * Since: 1.4
14956  */
14957 GList *
14958 clutter_actor_get_actions (ClutterActor *self)
14959 {
14960   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14961
14962   if (self->priv->actions == NULL)
14963     return NULL;
14964
14965   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14966 }
14967
14968 /**
14969  * clutter_actor_get_action:
14970  * @self: a #ClutterActor
14971  * @name: the name of the action to retrieve
14972  *
14973  * Retrieves the #ClutterAction with the given name in the list
14974  * of actions applied to @self
14975  *
14976  * Return value: (transfer none): a #ClutterAction for the given
14977  *   name, or %NULL. The returned #ClutterAction is owned by the
14978  *   actor and it should not be unreferenced directly
14979  *
14980  * Since: 1.4
14981  */
14982 ClutterAction *
14983 clutter_actor_get_action (ClutterActor *self,
14984                           const gchar  *name)
14985 {
14986   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14987   g_return_val_if_fail (name != NULL, NULL);
14988
14989   if (self->priv->actions == NULL)
14990     return NULL;
14991
14992   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14993 }
14994
14995 /**
14996  * clutter_actor_clear_actions:
14997  * @self: a #ClutterActor
14998  *
14999  * Clears the list of actions applied to @self
15000  *
15001  * Since: 1.4
15002  */
15003 void
15004 clutter_actor_clear_actions (ClutterActor *self)
15005 {
15006   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15007
15008   if (self->priv->actions == NULL)
15009     return;
15010
15011   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15012 }
15013
15014 /**
15015  * clutter_actor_add_constraint:
15016  * @self: a #ClutterActor
15017  * @constraint: a #ClutterConstraint
15018  *
15019  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15020  * to @self
15021  *
15022  * The #ClutterActor will hold a reference on the @constraint until
15023  * either clutter_actor_remove_constraint() or
15024  * clutter_actor_clear_constraints() is called.
15025  *
15026  * Since: 1.4
15027  */
15028 void
15029 clutter_actor_add_constraint (ClutterActor      *self,
15030                               ClutterConstraint *constraint)
15031 {
15032   ClutterActorPrivate *priv;
15033
15034   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15035   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15036
15037   priv = self->priv;
15038
15039   if (priv->constraints == NULL)
15040     {
15041       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15042       priv->constraints->actor = self;
15043     }
15044
15045   _clutter_meta_group_add_meta (priv->constraints,
15046                                 CLUTTER_ACTOR_META (constraint));
15047   clutter_actor_queue_relayout (self);
15048
15049   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15050 }
15051
15052 /**
15053  * clutter_actor_add_constraint_with_name:
15054  * @self: a #ClutterActor
15055  * @name: the name to set on the constraint
15056  * @constraint: a #ClutterConstraint
15057  *
15058  * A convenience function for setting the name of a #ClutterConstraint
15059  * while adding it to the list of constraints applied to @self
15060  *
15061  * This function is the logical equivalent of:
15062  *
15063  * |[
15064  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15065  *   clutter_actor_add_constraint (self, constraint);
15066  * ]|
15067  *
15068  * Since: 1.4
15069  */
15070 void
15071 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15072                                         const gchar       *name,
15073                                         ClutterConstraint *constraint)
15074 {
15075   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15076   g_return_if_fail (name != NULL);
15077   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15078
15079   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15080   clutter_actor_add_constraint (self, constraint);
15081 }
15082
15083 /**
15084  * clutter_actor_remove_constraint:
15085  * @self: a #ClutterActor
15086  * @constraint: a #ClutterConstraint
15087  *
15088  * Removes @constraint from the list of constraints applied to @self
15089  *
15090  * The reference held by @self on the #ClutterConstraint will be released
15091  *
15092  * Since: 1.4
15093  */
15094 void
15095 clutter_actor_remove_constraint (ClutterActor      *self,
15096                                  ClutterConstraint *constraint)
15097 {
15098   ClutterActorPrivate *priv;
15099
15100   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15101   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15102
15103   priv = self->priv;
15104
15105   if (priv->constraints == NULL)
15106     return;
15107
15108   _clutter_meta_group_remove_meta (priv->constraints,
15109                                    CLUTTER_ACTOR_META (constraint));
15110
15111   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15112     g_clear_object (&priv->constraints);
15113
15114   clutter_actor_queue_relayout (self);
15115
15116   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15117 }
15118
15119 /**
15120  * clutter_actor_remove_constraint_by_name:
15121  * @self: a #ClutterActor
15122  * @name: the name of the constraint to remove
15123  *
15124  * Removes the #ClutterConstraint with the given name from the list
15125  * of constraints applied to @self
15126  *
15127  * Since: 1.4
15128  */
15129 void
15130 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15131                                          const gchar  *name)
15132 {
15133   ClutterActorPrivate *priv;
15134   ClutterActorMeta *meta;
15135
15136   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15137   g_return_if_fail (name != NULL);
15138
15139   priv = self->priv;
15140
15141   if (priv->constraints == NULL)
15142     return;
15143
15144   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15145   if (meta == NULL)
15146     return;
15147
15148   _clutter_meta_group_remove_meta (priv->constraints, meta);
15149   clutter_actor_queue_relayout (self);
15150 }
15151
15152 /**
15153  * clutter_actor_get_constraints:
15154  * @self: a #ClutterActor
15155  *
15156  * Retrieves the list of constraints applied to @self
15157  *
15158  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15159  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15160  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15161  *   allocated by the returned #GList
15162  *
15163  * Since: 1.4
15164  */
15165 GList *
15166 clutter_actor_get_constraints (ClutterActor *self)
15167 {
15168   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15169
15170   if (self->priv->constraints == NULL)
15171     return NULL;
15172
15173   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15174 }
15175
15176 /**
15177  * clutter_actor_get_constraint:
15178  * @self: a #ClutterActor
15179  * @name: the name of the constraint to retrieve
15180  *
15181  * Retrieves the #ClutterConstraint with the given name in the list
15182  * of constraints applied to @self
15183  *
15184  * Return value: (transfer none): a #ClutterConstraint for the given
15185  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15186  *   actor and it should not be unreferenced directly
15187  *
15188  * Since: 1.4
15189  */
15190 ClutterConstraint *
15191 clutter_actor_get_constraint (ClutterActor *self,
15192                               const gchar  *name)
15193 {
15194   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15195   g_return_val_if_fail (name != NULL, NULL);
15196
15197   if (self->priv->constraints == NULL)
15198     return NULL;
15199
15200   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15201 }
15202
15203 /**
15204  * clutter_actor_clear_constraints:
15205  * @self: a #ClutterActor
15206  *
15207  * Clears the list of constraints applied to @self
15208  *
15209  * Since: 1.4
15210  */
15211 void
15212 clutter_actor_clear_constraints (ClutterActor *self)
15213 {
15214   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15215
15216   if (self->priv->constraints == NULL)
15217     return;
15218
15219   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15220
15221   clutter_actor_queue_relayout (self);
15222 }
15223
15224 /**
15225  * clutter_actor_set_clip_to_allocation:
15226  * @self: a #ClutterActor
15227  * @clip_set: %TRUE to apply a clip tracking the allocation
15228  *
15229  * Sets whether @self should be clipped to the same size as its
15230  * allocation
15231  *
15232  * Since: 1.4
15233  */
15234 void
15235 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15236                                       gboolean      clip_set)
15237 {
15238   ClutterActorPrivate *priv;
15239
15240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15241
15242   clip_set = !!clip_set;
15243
15244   priv = self->priv;
15245
15246   if (priv->clip_to_allocation != clip_set)
15247     {
15248       priv->clip_to_allocation = clip_set;
15249
15250       clutter_actor_queue_redraw (self);
15251
15252       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15253     }
15254 }
15255
15256 /**
15257  * clutter_actor_get_clip_to_allocation:
15258  * @self: a #ClutterActor
15259  *
15260  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15261  *
15262  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15263  *
15264  * Since: 1.4
15265  */
15266 gboolean
15267 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15268 {
15269   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15270
15271   return self->priv->clip_to_allocation;
15272 }
15273
15274 /**
15275  * clutter_actor_add_effect:
15276  * @self: a #ClutterActor
15277  * @effect: a #ClutterEffect
15278  *
15279  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15280  *
15281  * The #ClutterActor will hold a reference on the @effect until either
15282  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15283  * called.
15284  *
15285  * Since: 1.4
15286  */
15287 void
15288 clutter_actor_add_effect (ClutterActor  *self,
15289                           ClutterEffect *effect)
15290 {
15291   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15292   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15293
15294   _clutter_actor_add_effect_internal (self, effect);
15295
15296   clutter_actor_queue_redraw (self);
15297
15298   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15299 }
15300
15301 /**
15302  * clutter_actor_add_effect_with_name:
15303  * @self: a #ClutterActor
15304  * @name: the name to set on the effect
15305  * @effect: a #ClutterEffect
15306  *
15307  * A convenience function for setting the name of a #ClutterEffect
15308  * while adding it to the list of effectss applied to @self
15309  *
15310  * This function is the logical equivalent of:
15311  *
15312  * |[
15313  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15314  *   clutter_actor_add_effect (self, effect);
15315  * ]|
15316  *
15317  * Since: 1.4
15318  */
15319 void
15320 clutter_actor_add_effect_with_name (ClutterActor  *self,
15321                                     const gchar   *name,
15322                                     ClutterEffect *effect)
15323 {
15324   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15325   g_return_if_fail (name != NULL);
15326   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15327
15328   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15329   clutter_actor_add_effect (self, effect);
15330 }
15331
15332 /**
15333  * clutter_actor_remove_effect:
15334  * @self: a #ClutterActor
15335  * @effect: a #ClutterEffect
15336  *
15337  * Removes @effect from the list of effects applied to @self
15338  *
15339  * The reference held by @self on the #ClutterEffect will be released
15340  *
15341  * Since: 1.4
15342  */
15343 void
15344 clutter_actor_remove_effect (ClutterActor  *self,
15345                              ClutterEffect *effect)
15346 {
15347   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15348   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15349
15350   _clutter_actor_remove_effect_internal (self, effect);
15351
15352   clutter_actor_queue_redraw (self);
15353
15354   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15355 }
15356
15357 /**
15358  * clutter_actor_remove_effect_by_name:
15359  * @self: a #ClutterActor
15360  * @name: the name of the effect to remove
15361  *
15362  * Removes the #ClutterEffect with the given name from the list
15363  * of effects applied to @self
15364  *
15365  * Since: 1.4
15366  */
15367 void
15368 clutter_actor_remove_effect_by_name (ClutterActor *self,
15369                                      const gchar  *name)
15370 {
15371   ClutterActorPrivate *priv;
15372   ClutterActorMeta *meta;
15373
15374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15375   g_return_if_fail (name != NULL);
15376
15377   priv = self->priv;
15378
15379   if (priv->effects == NULL)
15380     return;
15381
15382   meta = _clutter_meta_group_get_meta (priv->effects, name);
15383   if (meta == NULL)
15384     return;
15385
15386   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15387 }
15388
15389 /**
15390  * clutter_actor_get_effects:
15391  * @self: a #ClutterActor
15392  *
15393  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15394  *
15395  * Return value: (transfer container) (element-type Clutter.Effect): a list
15396  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15397  *   list are owned by Clutter and they should not be freed. You should
15398  *   free the returned list using g_list_free() when done
15399  *
15400  * Since: 1.4
15401  */
15402 GList *
15403 clutter_actor_get_effects (ClutterActor *self)
15404 {
15405   ClutterActorPrivate *priv;
15406
15407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15408
15409   priv = self->priv;
15410
15411   if (priv->effects == NULL)
15412     return NULL;
15413
15414   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15415 }
15416
15417 /**
15418  * clutter_actor_get_effect:
15419  * @self: a #ClutterActor
15420  * @name: the name of the effect to retrieve
15421  *
15422  * Retrieves the #ClutterEffect with the given name in the list
15423  * of effects applied to @self
15424  *
15425  * Return value: (transfer none): a #ClutterEffect for the given
15426  *   name, or %NULL. The returned #ClutterEffect is owned by the
15427  *   actor and it should not be unreferenced directly
15428  *
15429  * Since: 1.4
15430  */
15431 ClutterEffect *
15432 clutter_actor_get_effect (ClutterActor *self,
15433                           const gchar  *name)
15434 {
15435   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15436   g_return_val_if_fail (name != NULL, NULL);
15437
15438   if (self->priv->effects == NULL)
15439     return NULL;
15440
15441   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15442 }
15443
15444 /**
15445  * clutter_actor_clear_effects:
15446  * @self: a #ClutterActor
15447  *
15448  * Clears the list of effects applied to @self
15449  *
15450  * Since: 1.4
15451  */
15452 void
15453 clutter_actor_clear_effects (ClutterActor *self)
15454 {
15455   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15456
15457   if (self->priv->effects == NULL)
15458     return;
15459
15460   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15461
15462   clutter_actor_queue_redraw (self);
15463 }
15464
15465 /**
15466  * clutter_actor_has_key_focus:
15467  * @self: a #ClutterActor
15468  *
15469  * Checks whether @self is the #ClutterActor that has key focus
15470  *
15471  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15472  *
15473  * Since: 1.4
15474  */
15475 gboolean
15476 clutter_actor_has_key_focus (ClutterActor *self)
15477 {
15478   ClutterActor *stage;
15479
15480   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15481
15482   stage = _clutter_actor_get_stage_internal (self);
15483   if (stage == NULL)
15484     return FALSE;
15485
15486   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15487 }
15488
15489 static gboolean
15490 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15491                                       ClutterPaintVolume *pv)
15492 {
15493   ClutterActorPrivate *priv = self->priv;
15494
15495   /* Actors are only expected to report a valid paint volume
15496    * while they have a valid allocation. */
15497   if (G_UNLIKELY (priv->needs_allocation))
15498     {
15499       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15500                     "Actor needs allocation",
15501                     _clutter_actor_get_debug_name (self));
15502       return FALSE;
15503     }
15504
15505   /* Check if there are any handlers connected to the paint
15506    * signal. If there are then all bets are off for what the paint
15507    * volume for this actor might possibly be!
15508    *
15509    * XXX: It's expected that this is going to end up being quite a
15510    * costly check to have to do here, but we haven't come up with
15511    * another solution that can reliably catch paint signal handlers at
15512    * the right time to either avoid artefacts due to invalid stage
15513    * clipping or due to incorrect culling.
15514    *
15515    * Previously we checked in clutter_actor_paint(), but at that time
15516    * we may already be using a stage clip that could be derived from
15517    * an invalid paint-volume. We used to try and handle that by
15518    * queuing a follow up, unclipped, redraw but still the previous
15519    * checking wasn't enough to catch invalid volumes involved in
15520    * culling (considering that containers may derive their volume from
15521    * children that haven't yet been painted)
15522    *
15523    * Longer term, improved solutions could be:
15524    * - Disallow painting in the paint signal, only allow using it
15525    *   for tracking when paints happen. We can add another API that
15526    *   allows monkey patching the paint of arbitrary actors but in a
15527    *   more controlled way and that also supports modifying the
15528    *   paint-volume.
15529    * - If we could be notified somehow when signal handlers are
15530    *   connected we wouldn't have to poll for handlers like this.
15531    */
15532   if (g_signal_has_handler_pending (self,
15533                                     actor_signals[PAINT],
15534                                     0,
15535                                     TRUE))
15536     {
15537       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15538                     "Actor has \"paint\" signal handlers",
15539                     _clutter_actor_get_debug_name (self));
15540       return FALSE;
15541     }
15542
15543   _clutter_paint_volume_init_static (pv, self);
15544
15545   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15546     {
15547       clutter_paint_volume_free (pv);
15548       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15549                     "Actor failed to report a volume",
15550                     _clutter_actor_get_debug_name (self));
15551       return FALSE;
15552     }
15553
15554   /* since effects can modify the paint volume, we allow them to actually
15555    * do this by making get_paint_volume() "context sensitive"
15556    */
15557   if (priv->effects != NULL)
15558     {
15559       if (priv->current_effect != NULL)
15560         {
15561           const GList *effects, *l;
15562
15563           /* if we are being called from within the paint sequence of
15564            * an actor, get the paint volume up to the current effect
15565            */
15566           effects = _clutter_meta_group_peek_metas (priv->effects);
15567           for (l = effects;
15568                l != NULL || (l != NULL && l->data != priv->current_effect);
15569                l = l->next)
15570             {
15571               if (!_clutter_effect_get_paint_volume (l->data, pv))
15572                 {
15573                   clutter_paint_volume_free (pv);
15574                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15575                                 "Effect (%s) failed to report a volume",
15576                                 _clutter_actor_get_debug_name (self),
15577                                 _clutter_actor_meta_get_debug_name (l->data));
15578                   return FALSE;
15579                 }
15580             }
15581         }
15582       else
15583         {
15584           const GList *effects, *l;
15585
15586           /* otherwise, get the cumulative volume */
15587           effects = _clutter_meta_group_peek_metas (priv->effects);
15588           for (l = effects; l != NULL; l = l->next)
15589             if (!_clutter_effect_get_paint_volume (l->data, pv))
15590               {
15591                 clutter_paint_volume_free (pv);
15592                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15593                               "Effect (%s) failed to report a volume",
15594                               _clutter_actor_get_debug_name (self),
15595                               _clutter_actor_meta_get_debug_name (l->data));
15596                 return FALSE;
15597               }
15598         }
15599     }
15600
15601   return TRUE;
15602 }
15603
15604 /* The public clutter_actor_get_paint_volume API returns a const
15605  * pointer since we return a pointer directly to the cached
15606  * PaintVolume associated with the actor and don't want the user to
15607  * inadvertently modify it, but for internal uses we sometimes need
15608  * access to the same PaintVolume but need to apply some book-keeping
15609  * modifications to it so we don't want a const pointer.
15610  */
15611 static ClutterPaintVolume *
15612 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15613 {
15614   ClutterActorPrivate *priv;
15615
15616   priv = self->priv;
15617
15618   if (priv->paint_volume_valid)
15619     clutter_paint_volume_free (&priv->paint_volume);
15620
15621   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15622     {
15623       priv->paint_volume_valid = TRUE;
15624       return &priv->paint_volume;
15625     }
15626   else
15627     {
15628       priv->paint_volume_valid = FALSE;
15629       return NULL;
15630     }
15631 }
15632
15633 /**
15634  * clutter_actor_get_paint_volume:
15635  * @self: a #ClutterActor
15636  *
15637  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15638  * when a paint volume can't be determined.
15639  *
15640  * The paint volume is defined as the 3D space occupied by an actor
15641  * when being painted.
15642  *
15643  * This function will call the <function>get_paint_volume()</function>
15644  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15645  * should not usually care about overriding the default implementation,
15646  * unless they are, for instance: painting outside their allocation, or
15647  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15648  * 3D depth).
15649  *
15650  * <note>2D actors overriding <function>get_paint_volume()</function>
15651  * ensure their volume has a depth of 0. (This will be true so long as
15652  * you don't call clutter_paint_volume_set_depth().)</note>
15653  *
15654  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15655  *   or %NULL if no volume could be determined. The returned pointer
15656  *   is not guaranteed to be valid across multiple frames; if you want
15657  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15658  *
15659  * Since: 1.6
15660  */
15661 const ClutterPaintVolume *
15662 clutter_actor_get_paint_volume (ClutterActor *self)
15663 {
15664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15665
15666   return _clutter_actor_get_paint_volume_mutable (self);
15667 }
15668
15669 /**
15670  * clutter_actor_get_transformed_paint_volume:
15671  * @self: a #ClutterActor
15672  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15673  *    (or %NULL for the stage)
15674  *
15675  * Retrieves the 3D paint volume of an actor like
15676  * clutter_actor_get_paint_volume() does (Please refer to the
15677  * documentation of clutter_actor_get_paint_volume() for more
15678  * details.) and it additionally transforms the paint volume into the
15679  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15680  * is passed for @relative_to_ancestor)
15681  *
15682  * This can be used by containers that base their paint volume on
15683  * the volume of their children. Such containers can query the
15684  * transformed paint volume of all of its children and union them
15685  * together using clutter_paint_volume_union().
15686  *
15687  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15688  *   or %NULL if no volume could be determined. The returned pointer is
15689  *   not guaranteed to be valid across multiple frames; if you wish to
15690  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15691  *
15692  * Since: 1.6
15693  */
15694 const ClutterPaintVolume *
15695 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15696                                             ClutterActor *relative_to_ancestor)
15697 {
15698   const ClutterPaintVolume *volume;
15699   ClutterActor *stage;
15700   ClutterPaintVolume *transformed_volume;
15701
15702   stage = _clutter_actor_get_stage_internal (self);
15703   if (G_UNLIKELY (stage == NULL))
15704     return NULL;
15705
15706   if (relative_to_ancestor == NULL)
15707     relative_to_ancestor = stage;
15708
15709   volume = clutter_actor_get_paint_volume (self);
15710   if (volume == NULL)
15711     return NULL;
15712
15713   transformed_volume =
15714     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15715
15716   _clutter_paint_volume_copy_static (volume, transformed_volume);
15717
15718   _clutter_paint_volume_transform_relative (transformed_volume,
15719                                             relative_to_ancestor);
15720
15721   return transformed_volume;
15722 }
15723
15724 /**
15725  * clutter_actor_get_paint_box:
15726  * @self: a #ClutterActor
15727  * @box: (out): return location for a #ClutterActorBox
15728  *
15729  * Retrieves the paint volume of the passed #ClutterActor, and
15730  * transforms it into a 2D bounding box in stage coordinates.
15731  *
15732  * This function is useful to determine the on screen area occupied by
15733  * the actor. The box is only an approximation and may often be
15734  * considerably larger due to the optimizations used to calculate the
15735  * box. The box is never smaller though, so it can reliably be used
15736  * for culling.
15737  *
15738  * There are times when a 2D paint box can't be determined, e.g.
15739  * because the actor isn't yet parented under a stage or because
15740  * the actor is unable to determine a paint volume.
15741  *
15742  * Return value: %TRUE if a 2D paint box could be determined, else
15743  * %FALSE.
15744  *
15745  * Since: 1.6
15746  */
15747 gboolean
15748 clutter_actor_get_paint_box (ClutterActor    *self,
15749                              ClutterActorBox *box)
15750 {
15751   ClutterActor *stage;
15752   ClutterPaintVolume *pv;
15753
15754   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15755   g_return_val_if_fail (box != NULL, FALSE);
15756
15757   stage = _clutter_actor_get_stage_internal (self);
15758   if (G_UNLIKELY (!stage))
15759     return FALSE;
15760
15761   pv = _clutter_actor_get_paint_volume_mutable (self);
15762   if (G_UNLIKELY (!pv))
15763     return FALSE;
15764
15765   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15766
15767   return TRUE;
15768 }
15769
15770 /**
15771  * clutter_actor_has_overlaps:
15772  * @self: A #ClutterActor
15773  *
15774  * Asks the actor's implementation whether it may contain overlapping
15775  * primitives.
15776  *
15777  * For example; Clutter may use this to determine whether the painting
15778  * should be redirected to an offscreen buffer to correctly implement
15779  * the opacity property.
15780  *
15781  * Custom actors can override the default response by implementing the
15782  * #ClutterActor <function>has_overlaps</function> virtual function. See
15783  * clutter_actor_set_offscreen_redirect() for more information.
15784  *
15785  * Return value: %TRUE if the actor may have overlapping primitives, and
15786  *   %FALSE otherwise
15787  *
15788  * Since: 1.8
15789  */
15790 gboolean
15791 clutter_actor_has_overlaps (ClutterActor *self)
15792 {
15793   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15794
15795   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15796 }
15797
15798 /**
15799  * clutter_actor_has_effects:
15800  * @self: A #ClutterActor
15801  *
15802  * Returns whether the actor has any effects applied.
15803  *
15804  * Return value: %TRUE if the actor has any effects,
15805  *   %FALSE otherwise
15806  *
15807  * Since: 1.10
15808  */
15809 gboolean
15810 clutter_actor_has_effects (ClutterActor *self)
15811 {
15812   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15813
15814   if (self->priv->effects == NULL)
15815     return FALSE;
15816
15817   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15818 }
15819
15820 /**
15821  * clutter_actor_has_constraints:
15822  * @self: A #ClutterActor
15823  *
15824  * Returns whether the actor has any constraints applied.
15825  *
15826  * Return value: %TRUE if the actor has any constraints,
15827  *   %FALSE otherwise
15828  *
15829  * Since: 1.10
15830  */
15831 gboolean
15832 clutter_actor_has_constraints (ClutterActor *self)
15833 {
15834   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15835
15836   return self->priv->constraints != NULL;
15837 }
15838
15839 /**
15840  * clutter_actor_has_actions:
15841  * @self: A #ClutterActor
15842  *
15843  * Returns whether the actor has any actions applied.
15844  *
15845  * Return value: %TRUE if the actor has any actions,
15846  *   %FALSE otherwise
15847  *
15848  * Since: 1.10
15849  */
15850 gboolean
15851 clutter_actor_has_actions (ClutterActor *self)
15852 {
15853   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15854
15855   return self->priv->actions != NULL;
15856 }
15857
15858 /**
15859  * clutter_actor_get_n_children:
15860  * @self: a #ClutterActor
15861  *
15862  * Retrieves the number of children of @self.
15863  *
15864  * Return value: the number of children of an actor
15865  *
15866  * Since: 1.10
15867  */
15868 gint
15869 clutter_actor_get_n_children (ClutterActor *self)
15870 {
15871   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15872
15873   return self->priv->n_children;
15874 }
15875
15876 /**
15877  * clutter_actor_get_child_at_index:
15878  * @self: a #ClutterActor
15879  * @index_: the position in the list of children
15880  *
15881  * Retrieves the actor at the given @index_ inside the list of
15882  * children of @self.
15883  *
15884  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15885  *
15886  * Since: 1.10
15887  */
15888 ClutterActor *
15889 clutter_actor_get_child_at_index (ClutterActor *self,
15890                                   gint          index_)
15891 {
15892   ClutterActor *iter;
15893   int i;
15894
15895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15896   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15897
15898   for (iter = self->priv->first_child, i = 0;
15899        iter != NULL && i < index_;
15900        iter = iter->priv->next_sibling, i += 1)
15901     ;
15902
15903   return iter;
15904 }
15905
15906 /*< private >
15907  * _clutter_actor_foreach_child:
15908  * @actor: The actor whos children you want to iterate
15909  * @callback: The function to call for each child
15910  * @user_data: Private data to pass to @callback
15911  *
15912  * Calls a given @callback once for each child of the specified @actor and
15913  * passing the @user_data pointer each time.
15914  *
15915  * Return value: returns %TRUE if all children were iterated, else
15916  *    %FALSE if a callback broke out of iteration early.
15917  */
15918 gboolean
15919 _clutter_actor_foreach_child (ClutterActor           *self,
15920                               ClutterForeachCallback  callback,
15921                               gpointer                user_data)
15922 {
15923   ClutterActor *iter;
15924   gboolean cont;
15925
15926   if (self->priv->first_child == NULL)
15927     return TRUE;
15928
15929   cont = TRUE;
15930   iter = self->priv->first_child;
15931
15932   /* we use this form so that it's safe to change the children
15933    * list while iterating it
15934    */
15935   while (cont && iter != NULL)
15936     {
15937       ClutterActor *next = iter->priv->next_sibling;
15938
15939       cont = callback (iter, user_data);
15940
15941       iter = next;
15942     }
15943
15944   return cont;
15945 }
15946
15947 #if 0
15948 /* For debugging purposes this gives us a simple way to print out
15949  * the scenegraph e.g in gdb using:
15950  * [|
15951  *   _clutter_actor_traverse (stage,
15952  *                            0,
15953  *                            clutter_debug_print_actor_cb,
15954  *                            NULL,
15955  *                            NULL);
15956  * |]
15957  */
15958 static ClutterActorTraverseVisitFlags
15959 clutter_debug_print_actor_cb (ClutterActor *actor,
15960                               int depth,
15961                               void *user_data)
15962 {
15963   g_print ("%*s%s:%p\n",
15964            depth * 2, "",
15965            _clutter_actor_get_debug_name (actor),
15966            actor);
15967
15968   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15969 }
15970 #endif
15971
15972 static void
15973 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15974                                  ClutterTraverseCallback callback,
15975                                  gpointer                user_data)
15976 {
15977   GQueue *queue = g_queue_new ();
15978   ClutterActor dummy;
15979   int current_depth = 0;
15980
15981   g_queue_push_tail (queue, actor);
15982   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15983
15984   while ((actor = g_queue_pop_head (queue)))
15985     {
15986       ClutterActorTraverseVisitFlags flags;
15987
15988       if (actor == &dummy)
15989         {
15990           current_depth++;
15991           g_queue_push_tail (queue, &dummy);
15992           continue;
15993         }
15994
15995       flags = callback (actor, current_depth, user_data);
15996       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15997         break;
15998       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15999         {
16000           ClutterActor *iter;
16001
16002           for (iter = actor->priv->first_child;
16003                iter != NULL;
16004                iter = iter->priv->next_sibling)
16005             {
16006               g_queue_push_tail (queue, iter);
16007             }
16008         }
16009     }
16010
16011   g_queue_free (queue);
16012 }
16013
16014 static ClutterActorTraverseVisitFlags
16015 _clutter_actor_traverse_depth (ClutterActor           *actor,
16016                                ClutterTraverseCallback before_children_callback,
16017                                ClutterTraverseCallback after_children_callback,
16018                                int                     current_depth,
16019                                gpointer                user_data)
16020 {
16021   ClutterActorTraverseVisitFlags flags;
16022
16023   flags = before_children_callback (actor, current_depth, user_data);
16024   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16025     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16026
16027   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16028     {
16029       ClutterActor *iter;
16030
16031       for (iter = actor->priv->first_child;
16032            iter != NULL;
16033            iter = iter->priv->next_sibling)
16034         {
16035           flags = _clutter_actor_traverse_depth (iter,
16036                                                  before_children_callback,
16037                                                  after_children_callback,
16038                                                  current_depth + 1,
16039                                                  user_data);
16040
16041           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16042             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16043         }
16044     }
16045
16046   if (after_children_callback)
16047     return after_children_callback (actor, current_depth, user_data);
16048   else
16049     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16050 }
16051
16052 /* _clutter_actor_traverse:
16053  * @actor: The actor to start traversing the graph from
16054  * @flags: These flags may affect how the traversal is done
16055  * @before_children_callback: A function to call before visiting the
16056  *   children of the current actor.
16057  * @after_children_callback: A function to call after visiting the
16058  *   children of the current actor. (Ignored if
16059  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16060  * @user_data: The private data to pass to the callbacks
16061  *
16062  * Traverses the scenegraph starting at the specified @actor and
16063  * descending through all its children and its children's children.
16064  * For each actor traversed @before_children_callback and
16065  * @after_children_callback are called with the specified
16066  * @user_data, before and after visiting that actor's children.
16067  *
16068  * The callbacks can return flags that affect the ongoing traversal
16069  * such as by skipping over an actors children or bailing out of
16070  * any further traversing.
16071  */
16072 void
16073 _clutter_actor_traverse (ClutterActor              *actor,
16074                          ClutterActorTraverseFlags  flags,
16075                          ClutterTraverseCallback    before_children_callback,
16076                          ClutterTraverseCallback    after_children_callback,
16077                          gpointer                   user_data)
16078 {
16079   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16080     _clutter_actor_traverse_breadth (actor,
16081                                      before_children_callback,
16082                                      user_data);
16083   else /* DEPTH_FIRST */
16084     _clutter_actor_traverse_depth (actor,
16085                                    before_children_callback,
16086                                    after_children_callback,
16087                                    0, /* start depth */
16088                                    user_data);
16089 }
16090
16091 static void
16092 on_layout_manager_changed (ClutterLayoutManager *manager,
16093                            ClutterActor         *self)
16094 {
16095   clutter_actor_queue_relayout (self);
16096 }
16097
16098 /**
16099  * clutter_actor_set_layout_manager:
16100  * @self: a #ClutterActor
16101  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16102  *
16103  * Sets the #ClutterLayoutManager delegate object that will be used to
16104  * lay out the children of @self.
16105  *
16106  * The #ClutterActor will take a reference on the passed @manager which
16107  * will be released either when the layout manager is removed, or when
16108  * the actor is destroyed.
16109  *
16110  * Since: 1.10
16111  */
16112 void
16113 clutter_actor_set_layout_manager (ClutterActor         *self,
16114                                   ClutterLayoutManager *manager)
16115 {
16116   ClutterActorPrivate *priv;
16117
16118   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16119   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16120
16121   priv = self->priv;
16122
16123   if (priv->layout_manager != NULL)
16124     {
16125       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16126                                             G_CALLBACK (on_layout_manager_changed),
16127                                             self);
16128       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16129       g_clear_object (&priv->layout_manager);
16130     }
16131
16132   priv->layout_manager = manager;
16133
16134   if (priv->layout_manager != NULL)
16135     {
16136       g_object_ref_sink (priv->layout_manager);
16137       clutter_layout_manager_set_container (priv->layout_manager,
16138                                             CLUTTER_CONTAINER (self));
16139       g_signal_connect (priv->layout_manager, "layout-changed",
16140                         G_CALLBACK (on_layout_manager_changed),
16141                         self);
16142     }
16143
16144   clutter_actor_queue_relayout (self);
16145
16146   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16147 }
16148
16149 /**
16150  * clutter_actor_get_layout_manager:
16151  * @self: a #ClutterActor
16152  *
16153  * Retrieves the #ClutterLayoutManager used by @self.
16154  *
16155  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16156  *   or %NULL
16157  *
16158  * Since: 1.10
16159  */
16160 ClutterLayoutManager *
16161 clutter_actor_get_layout_manager (ClutterActor *self)
16162 {
16163   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16164
16165   return self->priv->layout_manager;
16166 }
16167
16168 static const ClutterLayoutInfo default_layout_info = {
16169   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16170   { 0, 0, 0, 0 },               /* margin */
16171   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16172   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16173   FALSE, FALSE,                 /* expand */
16174   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16175   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16176 };
16177
16178 static void
16179 layout_info_free (gpointer data)
16180 {
16181   if (G_LIKELY (data != NULL))
16182     g_slice_free (ClutterLayoutInfo, data);
16183 }
16184
16185 /*< private >
16186  * _clutter_actor_get_layout_info:
16187  * @self: a #ClutterActor
16188  *
16189  * Retrieves a pointer to the ClutterLayoutInfo structure.
16190  *
16191  * If the actor does not have a ClutterLayoutInfo associated to it, one
16192  * will be created and initialized to the default values.
16193  *
16194  * This function should be used for setters.
16195  *
16196  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16197  * instead.
16198  *
16199  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16200  */
16201 ClutterLayoutInfo *
16202 _clutter_actor_get_layout_info (ClutterActor *self)
16203 {
16204   ClutterLayoutInfo *retval;
16205
16206   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16207   if (retval == NULL)
16208     {
16209       retval = g_slice_new (ClutterLayoutInfo);
16210
16211       *retval = default_layout_info;
16212
16213       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16214                                retval,
16215                                layout_info_free);
16216     }
16217
16218   return retval;
16219 }
16220
16221 /*< private >
16222  * _clutter_actor_get_layout_info_or_defaults:
16223  * @self: a #ClutterActor
16224  *
16225  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16226  *
16227  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16228  * then the default structure will be returned.
16229  *
16230  * This function should only be used for getters.
16231  *
16232  * Return value: a const pointer to the ClutterLayoutInfo structure
16233  */
16234 const ClutterLayoutInfo *
16235 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16236 {
16237   const ClutterLayoutInfo *info;
16238
16239   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16240   if (info == NULL)
16241     return &default_layout_info;
16242
16243   return info;
16244 }
16245
16246 /**
16247  * clutter_actor_set_x_align:
16248  * @self: a #ClutterActor
16249  * @x_align: the horizontal alignment policy
16250  *
16251  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16252  * actor received extra horizontal space.
16253  *
16254  * See also the #ClutterActor:x-align property.
16255  *
16256  * Since: 1.10
16257  */
16258 void
16259 clutter_actor_set_x_align (ClutterActor      *self,
16260                            ClutterActorAlign  x_align)
16261 {
16262   ClutterLayoutInfo *info;
16263
16264   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16265
16266   info = _clutter_actor_get_layout_info (self);
16267
16268   if (info->x_align != x_align)
16269     {
16270       info->x_align = x_align;
16271
16272       clutter_actor_queue_relayout (self);
16273
16274       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16275     }
16276 }
16277
16278 /**
16279  * clutter_actor_get_x_align:
16280  * @self: a #ClutterActor
16281  *
16282  * Retrieves the horizontal alignment policy set using
16283  * clutter_actor_set_x_align().
16284  *
16285  * Return value: the horizontal alignment policy.
16286  *
16287  * Since: 1.10
16288  */
16289 ClutterActorAlign
16290 clutter_actor_get_x_align (ClutterActor *self)
16291 {
16292   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16293
16294   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16295 }
16296
16297 /**
16298  * clutter_actor_set_y_align:
16299  * @self: a #ClutterActor
16300  * @y_align: the vertical alignment policy
16301  *
16302  * Sets the vertical alignment policy of a #ClutterActor, in case the
16303  * actor received extra vertical space.
16304  *
16305  * See also the #ClutterActor:y-align property.
16306  *
16307  * Since: 1.10
16308  */
16309 void
16310 clutter_actor_set_y_align (ClutterActor      *self,
16311                            ClutterActorAlign  y_align)
16312 {
16313   ClutterLayoutInfo *info;
16314
16315   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16316
16317   info = _clutter_actor_get_layout_info (self);
16318
16319   if (info->y_align != y_align)
16320     {
16321       info->y_align = y_align;
16322
16323       clutter_actor_queue_relayout (self);
16324
16325       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16326     }
16327 }
16328
16329 /**
16330  * clutter_actor_get_y_align:
16331  * @self: a #ClutterActor
16332  *
16333  * Retrieves the vertical alignment policy set using
16334  * clutter_actor_set_y_align().
16335  *
16336  * Return value: the vertical alignment policy.
16337  *
16338  * Since: 1.10
16339  */
16340 ClutterActorAlign
16341 clutter_actor_get_y_align (ClutterActor *self)
16342 {
16343   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16344
16345   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16346 }
16347
16348 /**
16349  * clutter_actor_set_margin:
16350  * @self: a #ClutterActor
16351  * @margin: a #ClutterMargin
16352  *
16353  * Sets all the components of the margin of a #ClutterActor.
16354  *
16355  * Since: 1.10
16356  */
16357 void
16358 clutter_actor_set_margin (ClutterActor        *self,
16359                           const ClutterMargin *margin)
16360 {
16361   ClutterLayoutInfo *info;
16362   gboolean changed;
16363   GObject *obj;
16364
16365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16366   g_return_if_fail (margin != NULL);
16367
16368   obj = G_OBJECT (self);
16369   changed = FALSE;
16370
16371   g_object_freeze_notify (obj);
16372
16373   info = _clutter_actor_get_layout_info (self);
16374
16375   if (info->margin.top != margin->top)
16376     {
16377       info->margin.top = margin->top;
16378       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16379       changed = TRUE;
16380     }
16381
16382   if (info->margin.right != margin->right)
16383     {
16384       info->margin.right = margin->right;
16385       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16386       changed = TRUE;
16387     }
16388
16389   if (info->margin.bottom != margin->bottom)
16390     {
16391       info->margin.bottom = margin->bottom;
16392       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16393       changed = TRUE;
16394     }
16395
16396   if (info->margin.left != margin->left)
16397     {
16398       info->margin.left = margin->left;
16399       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16400       changed = TRUE;
16401     }
16402
16403   if (changed)
16404     clutter_actor_queue_relayout (self);
16405
16406   g_object_thaw_notify (obj);
16407 }
16408
16409 /**
16410  * clutter_actor_get_margin:
16411  * @self: a #ClutterActor
16412  * @margin: (out caller-allocates): return location for a #ClutterMargin
16413  *
16414  * Retrieves all the components of the margin of a #ClutterActor.
16415  *
16416  * Since: 1.10
16417  */
16418 void
16419 clutter_actor_get_margin (ClutterActor  *self,
16420                           ClutterMargin *margin)
16421 {
16422   const ClutterLayoutInfo *info;
16423
16424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16425   g_return_if_fail (margin != NULL);
16426
16427   info = _clutter_actor_get_layout_info_or_defaults (self);
16428
16429   *margin = info->margin;
16430 }
16431
16432 /**
16433  * clutter_actor_set_margin_top:
16434  * @self: a #ClutterActor
16435  * @margin: the top margin
16436  *
16437  * Sets the margin from the top of a #ClutterActor.
16438  *
16439  * Since: 1.10
16440  */
16441 void
16442 clutter_actor_set_margin_top (ClutterActor *self,
16443                               gfloat        margin)
16444 {
16445   ClutterLayoutInfo *info;
16446
16447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16448   g_return_if_fail (margin >= 0.f);
16449
16450   info = _clutter_actor_get_layout_info (self);
16451
16452   if (info->margin.top == margin)
16453     return;
16454
16455   info->margin.top = margin;
16456
16457   clutter_actor_queue_relayout (self);
16458
16459   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16460 }
16461
16462 /**
16463  * clutter_actor_get_margin_top:
16464  * @self: a #ClutterActor
16465  *
16466  * Retrieves the top margin of a #ClutterActor.
16467  *
16468  * Return value: the top margin
16469  *
16470  * Since: 1.10
16471  */
16472 gfloat
16473 clutter_actor_get_margin_top (ClutterActor *self)
16474 {
16475   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16476
16477   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16478 }
16479
16480 /**
16481  * clutter_actor_set_margin_bottom:
16482  * @self: a #ClutterActor
16483  * @margin: the bottom margin
16484  *
16485  * Sets the margin from the bottom of a #ClutterActor.
16486  *
16487  * Since: 1.10
16488  */
16489 void
16490 clutter_actor_set_margin_bottom (ClutterActor *self,
16491                                  gfloat        margin)
16492 {
16493   ClutterLayoutInfo *info;
16494
16495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16496   g_return_if_fail (margin >= 0.f);
16497
16498   info = _clutter_actor_get_layout_info (self);
16499
16500   if (info->margin.bottom == margin)
16501     return;
16502
16503   info->margin.bottom = margin;
16504
16505   clutter_actor_queue_relayout (self);
16506
16507   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16508 }
16509
16510 /**
16511  * clutter_actor_get_margin_bottom:
16512  * @self: a #ClutterActor
16513  *
16514  * Retrieves the bottom margin of a #ClutterActor.
16515  *
16516  * Return value: the bottom margin
16517  *
16518  * Since: 1.10
16519  */
16520 gfloat
16521 clutter_actor_get_margin_bottom (ClutterActor *self)
16522 {
16523   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16524
16525   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16526 }
16527
16528 /**
16529  * clutter_actor_set_margin_left:
16530  * @self: a #ClutterActor
16531  * @margin: the left margin
16532  *
16533  * Sets the margin from the left of a #ClutterActor.
16534  *
16535  * Since: 1.10
16536  */
16537 void
16538 clutter_actor_set_margin_left (ClutterActor *self,
16539                                gfloat        margin)
16540 {
16541   ClutterLayoutInfo *info;
16542
16543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16544   g_return_if_fail (margin >= 0.f);
16545
16546   info = _clutter_actor_get_layout_info (self);
16547
16548   if (info->margin.left == margin)
16549     return;
16550
16551   info->margin.left = margin;
16552
16553   clutter_actor_queue_relayout (self);
16554
16555   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16556 }
16557
16558 /**
16559  * clutter_actor_get_margin_left:
16560  * @self: a #ClutterActor
16561  *
16562  * Retrieves the left margin of a #ClutterActor.
16563  *
16564  * Return value: the left margin
16565  *
16566  * Since: 1.10
16567  */
16568 gfloat
16569 clutter_actor_get_margin_left (ClutterActor *self)
16570 {
16571   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16572
16573   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16574 }
16575
16576 /**
16577  * clutter_actor_set_margin_right:
16578  * @self: a #ClutterActor
16579  * @margin: the right margin
16580  *
16581  * Sets the margin from the right of a #ClutterActor.
16582  *
16583  * Since: 1.10
16584  */
16585 void
16586 clutter_actor_set_margin_right (ClutterActor *self,
16587                                 gfloat        margin)
16588 {
16589   ClutterLayoutInfo *info;
16590
16591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16592   g_return_if_fail (margin >= 0.f);
16593
16594   info = _clutter_actor_get_layout_info (self);
16595
16596   if (info->margin.right == margin)
16597     return;
16598
16599   info->margin.right = margin;
16600
16601   clutter_actor_queue_relayout (self);
16602
16603   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16604 }
16605
16606 /**
16607  * clutter_actor_get_margin_right:
16608  * @self: a #ClutterActor
16609  *
16610  * Retrieves the right margin of a #ClutterActor.
16611  *
16612  * Return value: the right margin
16613  *
16614  * Since: 1.10
16615  */
16616 gfloat
16617 clutter_actor_get_margin_right (ClutterActor *self)
16618 {
16619   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16620
16621   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16622 }
16623
16624 static inline void
16625 clutter_actor_set_background_color_internal (ClutterActor *self,
16626                                              const ClutterColor *color)
16627 {
16628   ClutterActorPrivate *priv = self->priv;
16629   GObject *obj;
16630
16631   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16632     return;
16633
16634   obj = G_OBJECT (self);
16635
16636   priv->bg_color = *color;
16637   priv->bg_color_set = TRUE;
16638
16639   clutter_actor_queue_redraw (self);
16640
16641   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16642   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16643 }
16644
16645 /**
16646  * clutter_actor_set_background_color:
16647  * @self: a #ClutterActor
16648  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16649  *  set color
16650  *
16651  * Sets the background color of a #ClutterActor.
16652  *
16653  * The background color will be used to cover the whole allocation of the
16654  * actor. The default background color of an actor is transparent.
16655  *
16656  * To check whether an actor has a background color, you can use the
16657  * #ClutterActor:background-color-set actor property.
16658  *
16659  * The #ClutterActor:background-color property is animatable.
16660  *
16661  * Since: 1.10
16662  */
16663 void
16664 clutter_actor_set_background_color (ClutterActor       *self,
16665                                     const ClutterColor *color)
16666 {
16667   ClutterActorPrivate *priv;
16668   GObject *obj;
16669   GParamSpec *bg_color_pspec;
16670
16671   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16672
16673   obj = G_OBJECT (self);
16674
16675   priv = self->priv;
16676
16677   if (color == NULL)
16678     {
16679       priv->bg_color_set = FALSE;
16680       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16681       clutter_actor_queue_redraw (self);
16682       return;
16683     }
16684
16685   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16686   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16687     {
16688       _clutter_actor_create_transition (self, bg_color_pspec,
16689                                         &priv->bg_color,
16690                                         color);
16691     }
16692   else
16693     _clutter_actor_update_transition (self, bg_color_pspec, color);
16694
16695   clutter_actor_queue_redraw (self);
16696 }
16697
16698 /**
16699  * clutter_actor_get_background_color:
16700  * @self: a #ClutterActor
16701  * @color: (out caller-allocates): return location for a #ClutterColor
16702  *
16703  * Retrieves the color set using clutter_actor_set_background_color().
16704  *
16705  * Since: 1.10
16706  */
16707 void
16708 clutter_actor_get_background_color (ClutterActor *self,
16709                                     ClutterColor *color)
16710 {
16711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16712   g_return_if_fail (color != NULL);
16713
16714   *color = self->priv->bg_color;
16715 }
16716
16717 /**
16718  * clutter_actor_get_previous_sibling:
16719  * @self: a #ClutterActor
16720  *
16721  * Retrieves the sibling of @self that comes before it in the list
16722  * of children of @self's parent.
16723  *
16724  * The returned pointer is only valid until the scene graph changes; it
16725  * is not safe to modify the list of children of @self while iterating
16726  * it.
16727  *
16728  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16729  *
16730  * Since: 1.10
16731  */
16732 ClutterActor *
16733 clutter_actor_get_previous_sibling (ClutterActor *self)
16734 {
16735   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16736
16737   return self->priv->prev_sibling;
16738 }
16739
16740 /**
16741  * clutter_actor_get_next_sibling:
16742  * @self: a #ClutterActor
16743  *
16744  * Retrieves the sibling of @self that comes after it in the list
16745  * of children of @self's parent.
16746  *
16747  * The returned pointer is only valid until the scene graph changes; it
16748  * is not safe to modify the list of children of @self while iterating
16749  * it.
16750  *
16751  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16752  *
16753  * Since: 1.10
16754  */
16755 ClutterActor *
16756 clutter_actor_get_next_sibling (ClutterActor *self)
16757 {
16758   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16759
16760   return self->priv->next_sibling;
16761 }
16762
16763 /**
16764  * clutter_actor_get_first_child:
16765  * @self: a #ClutterActor
16766  *
16767  * Retrieves the first child of @self.
16768  *
16769  * The returned pointer is only valid until the scene graph changes; it
16770  * is not safe to modify the list of children of @self while iterating
16771  * it.
16772  *
16773  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16774  *
16775  * Since: 1.10
16776  */
16777 ClutterActor *
16778 clutter_actor_get_first_child (ClutterActor *self)
16779 {
16780   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16781
16782   return self->priv->first_child;
16783 }
16784
16785 /**
16786  * clutter_actor_get_last_child:
16787  * @self: a #ClutterActor
16788  *
16789  * Retrieves the last child of @self.
16790  *
16791  * The returned pointer is only valid until the scene graph changes; it
16792  * is not safe to modify the list of children of @self while iterating
16793  * it.
16794  *
16795  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16796  *
16797  * Since: 1.10
16798  */
16799 ClutterActor *
16800 clutter_actor_get_last_child (ClutterActor *self)
16801 {
16802   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16803
16804   return self->priv->last_child;
16805 }
16806
16807 /* easy way to have properly named fields instead of the dummy ones
16808  * we use in the public structure
16809  */
16810 typedef struct _RealActorIter
16811 {
16812   ClutterActor *root;           /* dummy1 */
16813   ClutterActor *current;        /* dummy2 */
16814   gpointer padding_1;           /* dummy3 */
16815   gint age;                     /* dummy4 */
16816   gpointer padding_2;           /* dummy5 */
16817 } RealActorIter;
16818
16819 /**
16820  * clutter_actor_iter_init:
16821  * @iter: a #ClutterActorIter
16822  * @root: a #ClutterActor
16823  *
16824  * Initializes a #ClutterActorIter, which can then be used to iterate
16825  * efficiently over a section of the scene graph, and associates it
16826  * with @root.
16827  *
16828  * Modifying the scene graph section that contains @root will invalidate
16829  * the iterator.
16830  *
16831  * |[
16832  *   ClutterActorIter iter;
16833  *   ClutterActor *child;
16834  *
16835  *   clutter_actor_iter_init (&iter, container);
16836  *   while (clutter_actor_iter_next (&iter, &child))
16837  *     {
16838  *       /&ast; do something with child &ast;/
16839  *     }
16840  * ]|
16841  *
16842  * Since: 1.10
16843  */
16844 void
16845 clutter_actor_iter_init (ClutterActorIter *iter,
16846                          ClutterActor     *root)
16847 {
16848   RealActorIter *ri = (RealActorIter *) iter;
16849
16850   g_return_if_fail (iter != NULL);
16851   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16852
16853   ri->root = root;
16854   ri->current = NULL;
16855   ri->age = root->priv->age;
16856 }
16857
16858 /**
16859  * clutter_actor_iter_next:
16860  * @iter: a #ClutterActorIter
16861  * @child: (out): return location for a #ClutterActor
16862  *
16863  * Advances the @iter and retrieves the next child of the root #ClutterActor
16864  * that was used to initialize the #ClutterActorIterator.
16865  *
16866  * If the iterator can advance, this function returns %TRUE and sets the
16867  * @child argument.
16868  *
16869  * If the iterator cannot advance, this function returns %FALSE, and
16870  * the contents of @child are undefined.
16871  *
16872  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16873  *
16874  * Since: 1.10
16875  */
16876 gboolean
16877 clutter_actor_iter_next (ClutterActorIter  *iter,
16878                          ClutterActor     **child)
16879 {
16880   RealActorIter *ri = (RealActorIter *) iter;
16881
16882   g_return_val_if_fail (iter != NULL, FALSE);
16883   g_return_val_if_fail (ri->root != NULL, FALSE);
16884 #ifndef G_DISABLE_ASSERT
16885   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16886 #endif
16887
16888   if (ri->current == NULL)
16889     ri->current = ri->root->priv->first_child;
16890   else
16891     ri->current = ri->current->priv->next_sibling;
16892
16893   if (child != NULL)
16894     *child = ri->current;
16895
16896   return ri->current != NULL;
16897 }
16898
16899 /**
16900  * clutter_actor_iter_prev:
16901  * @iter: a #ClutterActorIter
16902  * @child: (out): return location for a #ClutterActor
16903  *
16904  * Advances the @iter and retrieves the previous child of the root
16905  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16906  *
16907  * If the iterator can advance, this function returns %TRUE and sets the
16908  * @child argument.
16909  *
16910  * If the iterator cannot advance, this function returns %FALSE, and
16911  * the contents of @child are undefined.
16912  *
16913  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16914  *
16915  * Since: 1.10
16916  */
16917 gboolean
16918 clutter_actor_iter_prev (ClutterActorIter  *iter,
16919                          ClutterActor     **child)
16920 {
16921   RealActorIter *ri = (RealActorIter *) iter;
16922
16923   g_return_val_if_fail (iter != NULL, FALSE);
16924   g_return_val_if_fail (ri->root != NULL, FALSE);
16925 #ifndef G_DISABLE_ASSERT
16926   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16927 #endif
16928
16929   if (ri->current == NULL)
16930     ri->current = ri->root->priv->last_child;
16931   else
16932     ri->current = ri->current->priv->prev_sibling;
16933
16934   if (child != NULL)
16935     *child = ri->current;
16936
16937   return ri->current != NULL;
16938 }
16939
16940 /**
16941  * clutter_actor_iter_remove:
16942  * @iter: a #ClutterActorIter
16943  *
16944  * Safely removes the #ClutterActor currently pointer to by the iterator
16945  * from its parent.
16946  *
16947  * This function can only be called after clutter_actor_iter_next() or
16948  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16949  * than once for the same actor.
16950  *
16951  * This function will call clutter_actor_remove_child() internally.
16952  *
16953  * Since: 1.10
16954  */
16955 void
16956 clutter_actor_iter_remove (ClutterActorIter *iter)
16957 {
16958   RealActorIter *ri = (RealActorIter *) iter;
16959   ClutterActor *cur;
16960
16961   g_return_if_fail (iter != NULL);
16962   g_return_if_fail (ri->root != NULL);
16963 #ifndef G_DISABLE_ASSERT
16964   g_return_if_fail (ri->age == ri->root->priv->age);
16965 #endif
16966   g_return_if_fail (ri->current != NULL);
16967
16968   cur = ri->current;
16969
16970   if (cur != NULL)
16971     {
16972       ri->current = cur->priv->prev_sibling;
16973
16974       clutter_actor_remove_child_internal (ri->root, cur,
16975                                            REMOVE_CHILD_DEFAULT_FLAGS);
16976
16977       ri->age += 1;
16978     }
16979 }
16980
16981 /**
16982  * clutter_actor_iter_destroy:
16983  * @iter: a #ClutterActorIter
16984  *
16985  * Safely destroys the #ClutterActor currently pointer to by the iterator
16986  * from its parent.
16987  *
16988  * This function can only be called after clutter_actor_iter_next() or
16989  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16990  * than once for the same actor.
16991  *
16992  * This function will call clutter_actor_destroy() internally.
16993  *
16994  * Since: 1.10
16995  */
16996 void
16997 clutter_actor_iter_destroy (ClutterActorIter *iter)
16998 {
16999   RealActorIter *ri = (RealActorIter *) iter;
17000   ClutterActor *cur;
17001
17002   g_return_if_fail (iter != NULL);
17003   g_return_if_fail (ri->root != NULL);
17004 #ifndef G_DISABLE_ASSERT
17005   g_return_if_fail (ri->age == ri->root->priv->age);
17006 #endif
17007   g_return_if_fail (ri->current != NULL);
17008
17009   cur = ri->current;
17010
17011   if (cur != NULL)
17012     {
17013       ri->current = cur->priv->prev_sibling;
17014
17015       clutter_actor_destroy (cur);
17016
17017       ri->age += 1;
17018     }
17019 }
17020
17021 static const ClutterAnimationInfo default_animation_info = {
17022   NULL,         /* transitions */
17023   NULL,         /* states */
17024   NULL,         /* cur_state */
17025 };
17026
17027 static void
17028 clutter_animation_info_free (gpointer data)
17029 {
17030   if (data != NULL)
17031     {
17032       ClutterAnimationInfo *info = data;
17033
17034       if (info->transitions != NULL)
17035         g_hash_table_unref (info->transitions);
17036
17037       if (info->states != NULL)
17038         g_array_unref (info->states);
17039
17040       g_slice_free (ClutterAnimationInfo, info);
17041     }
17042 }
17043
17044 const ClutterAnimationInfo *
17045 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17046 {
17047   const ClutterAnimationInfo *res;
17048   GObject *obj = G_OBJECT (self);
17049
17050   res = g_object_get_qdata (obj, quark_actor_animation_info);
17051   if (res != NULL)
17052     return res;
17053
17054   return &default_animation_info;
17055 }
17056
17057 ClutterAnimationInfo *
17058 _clutter_actor_get_animation_info (ClutterActor *self)
17059 {
17060   GObject *obj = G_OBJECT (self);
17061   ClutterAnimationInfo *res;
17062
17063   res = g_object_get_qdata (obj, quark_actor_animation_info);
17064   if (res == NULL)
17065     {
17066       res = g_slice_new (ClutterAnimationInfo);
17067
17068       *res = default_animation_info;
17069
17070       g_object_set_qdata_full (obj, quark_actor_animation_info,
17071                                res,
17072                                clutter_animation_info_free);
17073     }
17074
17075   return res;
17076 }
17077
17078 ClutterTransition *
17079 _clutter_actor_get_transition (ClutterActor *actor,
17080                                GParamSpec   *pspec)
17081 {
17082   const ClutterAnimationInfo *info;
17083
17084   info = _clutter_actor_get_animation_info_or_defaults (actor);
17085
17086   if (info->transitions == NULL)
17087     return NULL;
17088
17089   return g_hash_table_lookup (info->transitions, pspec->name);
17090 }
17091
17092 typedef struct _TransitionClosure
17093 {
17094   ClutterActor *actor;
17095   ClutterTransition *transition;
17096   gchar *name;
17097   gulong completed_id;
17098 } TransitionClosure;
17099
17100 static void
17101 transition_closure_free (gpointer data)
17102 {
17103   if (G_LIKELY (data != NULL))
17104     {
17105       TransitionClosure *clos = data;
17106       ClutterTimeline *timeline;
17107
17108       timeline = CLUTTER_TIMELINE (clos->transition);
17109
17110       if (clutter_timeline_is_playing (timeline))
17111         clutter_timeline_stop (timeline);
17112
17113       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17114
17115       g_object_unref (clos->transition);
17116       g_free (clos->name);
17117
17118       g_slice_free (TransitionClosure, clos);
17119     }
17120 }
17121
17122 static void
17123 on_transition_completed (ClutterTransition *transition,
17124                          TransitionClosure *clos)
17125 {
17126   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17127   ClutterActor *actor = clos->actor;
17128   ClutterAnimationInfo *info;
17129   gint n_repeats, cur_repeat;
17130
17131   info = _clutter_actor_get_animation_info (actor);
17132
17133   /* reset the caches used by animations */
17134   clutter_actor_store_content_box (actor, NULL);
17135
17136   /* ensure that we remove the transition only at the end
17137    * of its run; we emit ::completed for every repeat
17138    */
17139   n_repeats = clutter_timeline_get_repeat_count (timeline);
17140   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17141
17142   if (cur_repeat == n_repeats)
17143     {
17144       if (clutter_transition_get_remove_on_complete (transition))
17145         {
17146           /* we take a reference here because removing the closure
17147            * will release the reference on the transition, and we
17148            * want the transition to survive the signal emission;
17149            * the master clock will release the last reference at
17150            * the end of the frame processing.
17151            */
17152           g_object_ref (transition);
17153           g_hash_table_remove (info->transitions, clos->name);
17154         }
17155     }
17156
17157   /* if it's the last transition then we clean up */
17158   if (g_hash_table_size (info->transitions) == 0)
17159     {
17160       g_hash_table_unref (info->transitions);
17161       info->transitions = NULL;
17162
17163       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17164                     _clutter_actor_get_debug_name (actor));
17165
17166       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17167     }
17168 }
17169
17170 void
17171 _clutter_actor_update_transition (ClutterActor *actor,
17172                                   GParamSpec   *pspec,
17173                                   ...)
17174 {
17175   TransitionClosure *clos;
17176   ClutterTimeline *timeline;
17177   ClutterInterval *interval;
17178   const ClutterAnimationInfo *info;
17179   va_list var_args;
17180   GType ptype;
17181   GValue initial = G_VALUE_INIT;
17182   GValue final = G_VALUE_INIT;
17183   char *error = NULL;
17184
17185   info = _clutter_actor_get_animation_info_or_defaults (actor);
17186
17187   if (info->transitions == NULL)
17188     return;
17189
17190   clos = g_hash_table_lookup (info->transitions, pspec->name);
17191   if (clos == NULL)
17192     return;
17193
17194   timeline = CLUTTER_TIMELINE (clos->transition);
17195
17196   va_start (var_args, pspec);
17197
17198   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17199
17200   g_value_init (&initial, ptype);
17201   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17202                                         pspec->name,
17203                                         &initial);
17204
17205   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17206   if (error != NULL)
17207     {
17208       g_critical ("%s: %s", G_STRLOC, error);
17209       g_free (error);
17210       goto out;
17211     }
17212
17213   interval = clutter_transition_get_interval (clos->transition);
17214   clutter_interval_set_initial_value (interval, &initial);
17215   clutter_interval_set_final_value (interval, &final);
17216
17217   /* if we're updating with an easing duration of zero milliseconds,
17218    * we just jump the timeline to the end and let it run its course
17219    */
17220   if (info->cur_state != NULL &&
17221       info->cur_state->easing_duration != 0)
17222     {
17223       guint cur_duration = clutter_timeline_get_duration (timeline);
17224       ClutterAnimationMode cur_mode =
17225         clutter_timeline_get_progress_mode (timeline);
17226
17227       if (cur_duration != info->cur_state->easing_duration)
17228         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17229
17230       if (cur_mode != info->cur_state->easing_mode)
17231         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17232
17233       clutter_timeline_rewind (timeline);
17234     }
17235   else
17236     {
17237       guint duration = clutter_timeline_get_duration (timeline);
17238
17239       clutter_timeline_advance (timeline, duration);
17240     }
17241
17242 out:
17243   g_value_unset (&initial);
17244   g_value_unset (&final);
17245
17246   va_end (var_args);
17247 }
17248
17249 /*< private >*
17250  * _clutter_actor_create_transition:
17251  * @actor: a #ClutterActor
17252  * @pspec: the property used for the transition
17253  * @...: initial and final state
17254  *
17255  * Creates a #ClutterTransition for the property represented by @pspec.
17256  *
17257  * Return value: a #ClutterTransition
17258  */
17259 ClutterTransition *
17260 _clutter_actor_create_transition (ClutterActor *actor,
17261                                   GParamSpec   *pspec,
17262                                   ...)
17263 {
17264   ClutterAnimationInfo *info;
17265   ClutterTransition *res = NULL;
17266   gboolean call_restore = FALSE;
17267   TransitionClosure *clos;
17268   va_list var_args;
17269
17270   info = _clutter_actor_get_animation_info (actor);
17271
17272   /* XXX - this will go away in 2.0
17273    *
17274    * if no state has been pushed, we assume that the easing state is
17275    * in "compatibility mode": all transitions have a duration of 0
17276    * msecs, which means that they happen immediately. in Clutter 2.0
17277    * this will turn into a g_assert(info->states != NULL), as every
17278    * actor will start with a predefined easing state
17279    */
17280   if (info->states == NULL)
17281     {
17282       clutter_actor_save_easing_state (actor);
17283       clutter_actor_set_easing_duration (actor, 0);
17284       call_restore = TRUE;
17285     }
17286
17287   if (info->transitions == NULL)
17288     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17289                                                NULL,
17290                                                transition_closure_free);
17291
17292   va_start (var_args, pspec);
17293
17294   clos = g_hash_table_lookup (info->transitions, pspec->name);
17295   if (clos == NULL)
17296     {
17297       ClutterTimeline *timeline;
17298       ClutterInterval *interval;
17299       GValue initial = G_VALUE_INIT;
17300       GValue final = G_VALUE_INIT;
17301       GType ptype;
17302       char *error;
17303
17304       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17305
17306       G_VALUE_COLLECT_INIT (&initial, ptype,
17307                             var_args, 0,
17308                             &error);
17309       if (error != NULL)
17310         {
17311           g_critical ("%s: %s", G_STRLOC, error);
17312           g_free (error);
17313           goto out;
17314         }
17315
17316       G_VALUE_COLLECT_INIT (&final, ptype,
17317                             var_args, 0,
17318                             &error);
17319
17320       if (error != NULL)
17321         {
17322           g_critical ("%s: %s", G_STRLOC, error);
17323           g_value_unset (&initial);
17324           g_free (error);
17325           goto out;
17326         }
17327
17328       /* if the current easing state has a duration of 0, then we don't
17329        * bother to create the transition, and we just set the final value
17330        * directly on the actor; we don't go through the Animatable
17331        * interface because we know we got here through an animatable
17332        * property.
17333        */
17334       if (info->cur_state->easing_duration == 0)
17335         {
17336           clutter_actor_set_animatable_property (actor,
17337                                                  pspec->param_id,
17338                                                  &final,
17339                                                  pspec);
17340           g_value_unset (&initial);
17341           g_value_unset (&final);
17342
17343           goto out;
17344         }
17345
17346       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17347
17348       g_value_unset (&initial);
17349       g_value_unset (&final);
17350
17351       res = clutter_property_transition_new (pspec->name);
17352
17353       clutter_transition_set_interval (res, interval);
17354       clutter_transition_set_remove_on_complete (res, TRUE);
17355
17356       timeline = CLUTTER_TIMELINE (res);
17357       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17358       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17359       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17360
17361       /* this will start the transition as well */
17362       clutter_actor_add_transition (actor, pspec->name, res);
17363
17364       /* the actor now owns the transition */
17365       g_object_unref (res);
17366     }
17367   else
17368     res = clos->transition;
17369
17370 out:
17371   if (call_restore)
17372     clutter_actor_restore_easing_state (actor);
17373
17374   va_end (var_args);
17375
17376   return res;
17377 }
17378
17379 /**
17380  * clutter_actor_add_transition:
17381  * @self: a #ClutterActor
17382  * @name: the name of the transition to add
17383  * @transition: the #ClutterTransition to add
17384  *
17385  * Adds a @transition to the #ClutterActor's list of animations.
17386  *
17387  * The @name string is a per-actor unique identifier of the @transition: only
17388  * one #ClutterTransition can be associated to the specified @name.
17389  *
17390  * The @transition will be started once added.
17391  *
17392  * This function will take a reference on the @transition.
17393  *
17394  * This function is usually called implicitly when modifying an animatable
17395  * property.
17396  *
17397  * Since: 1.10
17398  */
17399 void
17400 clutter_actor_add_transition (ClutterActor      *self,
17401                               const char        *name,
17402                               ClutterTransition *transition)
17403 {
17404   ClutterTimeline *timeline;
17405   TransitionClosure *clos;
17406   ClutterAnimationInfo *info;
17407
17408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17409   g_return_if_fail (name != NULL);
17410   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17411
17412   info = _clutter_actor_get_animation_info (self);
17413
17414   if (info->transitions == NULL)
17415     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17416                                                NULL,
17417                                                transition_closure_free);
17418
17419   if (g_hash_table_lookup (info->transitions, name) != NULL)
17420     {
17421       g_warning ("A transition with name '%s' already exists for "
17422                  "the actor '%s'",
17423                  name,
17424                  _clutter_actor_get_debug_name (self));
17425       return;
17426     }
17427
17428   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17429
17430   timeline = CLUTTER_TIMELINE (transition);
17431
17432   clos = g_slice_new (TransitionClosure);
17433   clos->actor = self;
17434   clos->transition = g_object_ref (transition);
17435   clos->name = g_strdup (name);
17436   clos->completed_id = g_signal_connect (timeline, "completed",
17437                                          G_CALLBACK (on_transition_completed),
17438                                          clos);
17439
17440   CLUTTER_NOTE (ANIMATION,
17441                 "Adding transition '%s' [%p] to actor '%s'",
17442                 clos->name,
17443                 clos->transition,
17444                 _clutter_actor_get_debug_name (self));
17445
17446   g_hash_table_insert (info->transitions, clos->name, clos);
17447   clutter_timeline_start (timeline);
17448 }
17449
17450 /**
17451  * clutter_actor_remove_transition:
17452  * @self: a #ClutterActor
17453  * @name: the name of the transition to remove
17454  *
17455  * Removes the transition stored inside a #ClutterActor using @name
17456  * identifier.
17457  *
17458  * If the transition is currently in progress, it will be stopped.
17459  *
17460  * This function releases the reference acquired when the transition
17461  * was added to the #ClutterActor.
17462  *
17463  * Since: 1.10
17464  */
17465 void
17466 clutter_actor_remove_transition (ClutterActor *self,
17467                                  const char   *name)
17468 {
17469   const ClutterAnimationInfo *info;
17470
17471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17472   g_return_if_fail (name != NULL);
17473
17474   info = _clutter_actor_get_animation_info_or_defaults (self);
17475
17476   if (info->transitions == NULL)
17477     return;
17478
17479   g_hash_table_remove (info->transitions, name);
17480 }
17481
17482 /**
17483  * clutter_actor_remove_all_transitions:
17484  * @self: a #ClutterActor
17485  *
17486  * Removes all transitions associated to @self.
17487  *
17488  * Since: 1.10
17489  */
17490 void
17491 clutter_actor_remove_all_transitions (ClutterActor *self)
17492 {
17493   const ClutterAnimationInfo *info;
17494
17495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17496
17497   info = _clutter_actor_get_animation_info_or_defaults (self);
17498   if (info->transitions == NULL)
17499     return;
17500
17501   g_hash_table_remove_all (info->transitions);
17502 }
17503
17504 /**
17505  * clutter_actor_set_easing_duration:
17506  * @self: a #ClutterActor
17507  * @msecs: the duration of the easing, or %NULL
17508  *
17509  * Sets the duration of the tweening for animatable properties
17510  * of @self for the current easing state.
17511  *
17512  * Since: 1.10
17513  */
17514 void
17515 clutter_actor_set_easing_duration (ClutterActor *self,
17516                                    guint         msecs)
17517 {
17518   ClutterAnimationInfo *info;
17519
17520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17521
17522   info = _clutter_actor_get_animation_info (self);
17523
17524   if (info->cur_state == NULL)
17525     {
17526       g_warning ("You must call clutter_actor_save_easing_state() prior "
17527                  "to calling clutter_actor_set_easing_duration().");
17528       return;
17529     }
17530
17531   if (info->cur_state->easing_duration != msecs)
17532     info->cur_state->easing_duration = msecs;
17533 }
17534
17535 /**
17536  * clutter_actor_get_easing_duration:
17537  * @self: a #ClutterActor
17538  *
17539  * Retrieves the duration of the tweening for animatable
17540  * properties of @self for the current easing state.
17541  *
17542  * Return value: the duration of the tweening, in milliseconds
17543  *
17544  * Since: 1.10
17545  */
17546 guint
17547 clutter_actor_get_easing_duration (ClutterActor *self)
17548 {
17549   const ClutterAnimationInfo *info;
17550
17551   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17552
17553   info = _clutter_actor_get_animation_info_or_defaults (self);
17554
17555   if (info->cur_state != NULL)
17556     return info->cur_state->easing_duration;
17557
17558   return 0;
17559 }
17560
17561 /**
17562  * clutter_actor_set_easing_mode:
17563  * @self: a #ClutterActor
17564  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17565  *
17566  * Sets the easing mode for the tweening of animatable properties
17567  * of @self.
17568  *
17569  * Since: 1.10
17570  */
17571 void
17572 clutter_actor_set_easing_mode (ClutterActor         *self,
17573                                ClutterAnimationMode  mode)
17574 {
17575   ClutterAnimationInfo *info;
17576
17577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17578   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17579   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17580
17581   info = _clutter_actor_get_animation_info (self);
17582
17583   if (info->cur_state == NULL)
17584     {
17585       g_warning ("You must call clutter_actor_save_easing_state() prior "
17586                  "to calling clutter_actor_set_easing_mode().");
17587       return;
17588     }
17589
17590   if (info->cur_state->easing_mode != mode)
17591     info->cur_state->easing_mode = mode;
17592 }
17593
17594 /**
17595  * clutter_actor_get_easing_mode:
17596  * @self: a #ClutterActor
17597  *
17598  * Retrieves the easing mode for the tweening of animatable properties
17599  * of @self for the current easing state.
17600  *
17601  * Return value: an easing mode
17602  *
17603  * Since: 1.10
17604  */
17605 ClutterAnimationMode
17606 clutter_actor_get_easing_mode (ClutterActor *self)
17607 {
17608   const ClutterAnimationInfo *info;
17609
17610   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17611
17612   info = _clutter_actor_get_animation_info_or_defaults (self);
17613
17614   if (info->cur_state != NULL)
17615     return info->cur_state->easing_mode;
17616
17617   return CLUTTER_EASE_OUT_CUBIC;
17618 }
17619
17620 /**
17621  * clutter_actor_set_easing_delay:
17622  * @self: a #ClutterActor
17623  * @msecs: the delay before the start of the tweening, in milliseconds
17624  *
17625  * Sets the delay that should be applied before tweening animatable
17626  * properties.
17627  *
17628  * Since: 1.10
17629  */
17630 void
17631 clutter_actor_set_easing_delay (ClutterActor *self,
17632                                 guint         msecs)
17633 {
17634   ClutterAnimationInfo *info;
17635
17636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17637
17638   info = _clutter_actor_get_animation_info (self);
17639
17640   if (info->cur_state == NULL)
17641     {
17642       g_warning ("You must call clutter_actor_save_easing_state() prior "
17643                  "to calling clutter_actor_set_easing_delay().");
17644       return;
17645     }
17646
17647   if (info->cur_state->easing_delay != msecs)
17648     info->cur_state->easing_delay = msecs;
17649 }
17650
17651 /**
17652  * clutter_actor_get_easing_delay:
17653  * @self: a #ClutterActor
17654  *
17655  * Retrieves the delay that should be applied when tweening animatable
17656  * properties.
17657  *
17658  * Return value: a delay, in milliseconds
17659  *
17660  * Since: 1.10
17661  */
17662 guint
17663 clutter_actor_get_easing_delay (ClutterActor *self)
17664 {
17665   const ClutterAnimationInfo *info;
17666
17667   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17668
17669   info = _clutter_actor_get_animation_info_or_defaults (self);
17670
17671   if (info->cur_state != NULL)
17672     return info->cur_state->easing_delay;
17673
17674   return 0;
17675 }
17676
17677 /**
17678  * clutter_actor_get_transition:
17679  * @self: a #ClutterActor
17680  * @name: the name of the transition
17681  *
17682  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17683  * transition @name.
17684  *
17685  * Transitions created for animatable properties use the name of the
17686  * property itself, for instance the code below:
17687  *
17688  * |[
17689  *   clutter_actor_set_easing_duration (actor, 1000);
17690  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17691  *
17692  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17693  *   g_signal_connect (transition, "completed",
17694  *                     G_CALLBACK (on_transition_complete),
17695  *                     actor);
17696  * ]|
17697  *
17698  * will call the <function>on_transition_complete</function> callback when
17699  * the transition is complete.
17700  *
17701  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17702  *   was found to match the passed name; the returned instance is owned
17703  *   by Clutter and it should not be freed
17704  *
17705  * Since: 1.10
17706  */
17707 ClutterTransition *
17708 clutter_actor_get_transition (ClutterActor *self,
17709                               const char   *name)
17710 {
17711   TransitionClosure *clos;
17712   const ClutterAnimationInfo *info;
17713
17714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17715   g_return_val_if_fail (name != NULL, NULL);
17716
17717   info = _clutter_actor_get_animation_info_or_defaults (self);
17718   if (info->transitions == NULL)
17719     return NULL;
17720
17721   clos = g_hash_table_lookup (info->transitions, name);
17722   if (clos == NULL)
17723     return NULL;
17724
17725   return clos->transition;
17726 }
17727
17728 /**
17729  * clutter_actor_save_easing_state:
17730  * @self: a #ClutterActor
17731  *
17732  * Saves the current easing state for animatable properties, and creates
17733  * a new state with the default values for easing mode and duration.
17734  *
17735  * Since: 1.10
17736  */
17737 void
17738 clutter_actor_save_easing_state (ClutterActor *self)
17739 {
17740   ClutterAnimationInfo *info;
17741   AState new_state;
17742
17743   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17744
17745   info = _clutter_actor_get_animation_info (self);
17746
17747   if (info->states == NULL)
17748     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17749
17750   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17751   new_state.easing_duration = 250;
17752   new_state.easing_delay = 0;
17753
17754   g_array_append_val (info->states, new_state);
17755
17756   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17757 }
17758
17759 /**
17760  * clutter_actor_restore_easing_state:
17761  * @self: a #ClutterActor
17762  *
17763  * Restores the easing state as it was prior to a call to
17764  * clutter_actor_save_easing_state().
17765  *
17766  * Since: 1.10
17767  */
17768 void
17769 clutter_actor_restore_easing_state (ClutterActor *self)
17770 {
17771   ClutterAnimationInfo *info;
17772
17773   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17774
17775   info = _clutter_actor_get_animation_info (self);
17776
17777   if (info->states == NULL)
17778     {
17779       g_critical ("The function clutter_actor_restore_easing_state() has "
17780                   "called without a previous call to "
17781                   "clutter_actor_save_easing_state().");
17782       return;
17783     }
17784
17785   g_array_remove_index (info->states, info->states->len - 1);
17786
17787   if (info->states->len > 0)
17788     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17789   else
17790     {
17791       g_array_unref (info->states);
17792       info->states = NULL;
17793       info->cur_state = NULL;
17794     }
17795 }
17796
17797 /**
17798  * clutter_actor_set_content:
17799  * @self: a #ClutterActor
17800  * @content: (allow-none): a #ClutterContent, or %NULL
17801  *
17802  * Sets the contents of a #ClutterActor.
17803  *
17804  * Since: 1.10
17805  */
17806 void
17807 clutter_actor_set_content (ClutterActor   *self,
17808                            ClutterContent *content)
17809 {
17810   ClutterActorPrivate *priv;
17811
17812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17813   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17814
17815   priv = self->priv;
17816
17817   if (priv->content != NULL)
17818     {
17819       _clutter_content_detached (priv->content, self);
17820       g_clear_object (&priv->content);
17821     }
17822
17823   priv->content = content;
17824
17825   if (priv->content != NULL)
17826     {
17827       g_object_ref (priv->content);
17828       _clutter_content_attached (priv->content, self);
17829     }
17830
17831   /* given that the content is always painted within the allocation,
17832    * we only need to queue a redraw here
17833    */
17834   clutter_actor_queue_redraw (self);
17835
17836   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17837
17838   /* if the content gravity is not resize-fill, and the new content has a
17839    * different preferred size than the previous one, then the content box
17840    * may have been changed. since we compute that lazily, we just notify
17841    * here, and let whomever watches :content-box do whatever they need to
17842    * do.
17843    */
17844   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17845     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17846 }
17847
17848 /**
17849  * clutter_actor_get_content:
17850  * @self: a #ClutterActor
17851  *
17852  * Retrieves the contents of @self.
17853  *
17854  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17855  *   or %NULL if none was set
17856  *
17857  * Since: 1.10
17858  */
17859 ClutterContent *
17860 clutter_actor_get_content (ClutterActor *self)
17861 {
17862   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17863
17864   return self->priv->content;
17865 }
17866
17867 /**
17868  * clutter_actor_set_content_gravity:
17869  * @self: a #ClutterActor
17870  * @gravity: the #ClutterContentGravity
17871  *
17872  * Sets the gravity of the #ClutterContent used by @self.
17873  *
17874  * See the description of the #ClutterActor:content-gravity property for
17875  * more information.
17876  *
17877  * The #ClutterActor:content-gravity property is animatable.
17878  *
17879  * Since: 1.10
17880  */
17881 void
17882 clutter_actor_set_content_gravity (ClutterActor *self,
17883                                    ClutterContentGravity  gravity)
17884 {
17885   ClutterActorPrivate *priv;
17886
17887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17888
17889   priv = self->priv;
17890
17891   if (priv->content_gravity == gravity)
17892     return;
17893
17894   priv->content_box_valid = FALSE;
17895
17896   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17897     {
17898       ClutterActorBox from_box, to_box;
17899
17900       clutter_actor_get_content_box (self, &from_box);
17901
17902       priv->content_gravity = gravity;
17903
17904       clutter_actor_get_content_box (self, &to_box);
17905
17906       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17907                                         &from_box,
17908                                         &to_box);
17909     }
17910   else
17911     {
17912       ClutterActorBox to_box;
17913
17914       priv->content_gravity = gravity;
17915
17916       clutter_actor_get_content_box (self, &to_box);
17917
17918       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17919                                         &to_box);
17920     }
17921
17922   clutter_actor_queue_redraw (self);
17923
17924   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17925 }
17926
17927 /**
17928  * clutter_actor_get_content_gravity:
17929  * @self: a #ClutterActor
17930  *
17931  * Retrieves the content gravity as set using
17932  * clutter_actor_get_content_gravity().
17933  *
17934  * Return value: the content gravity
17935  *
17936  * Since: 1.10
17937  */
17938 ClutterContentGravity
17939 clutter_actor_get_content_gravity (ClutterActor *self)
17940 {
17941   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17942                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17943
17944   return self->priv->content_gravity;
17945 }
17946
17947 /**
17948  * clutter_actor_get_content_box:
17949  * @self: a #ClutterActor
17950  * @box: (out caller-allocates): the return location for the bounding
17951  *   box for the #ClutterContent
17952  *
17953  * Retrieves the bounding box for the #ClutterContent of @self.
17954  *
17955  * The bounding box is relative to the actor's allocation.
17956  *
17957  * If no #ClutterContent is set for @self, or if @self has not been
17958  * allocated yet, then the result is undefined.
17959  *
17960  * The content box is guaranteed to be, at most, as big as the allocation
17961  * of the #ClutterActor.
17962  *
17963  * If the #ClutterContent used by the actor has a preferred size, then
17964  * it is possible to modify the content box by using the
17965  * #ClutterActor:content-gravity property.
17966  *
17967  * Since: 1.10
17968  */
17969 void
17970 clutter_actor_get_content_box (ClutterActor    *self,
17971                                ClutterActorBox *box)
17972 {
17973   ClutterActorPrivate *priv;
17974   gfloat content_w, content_h;
17975   gfloat alloc_w, alloc_h;
17976
17977   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17978   g_return_if_fail (box != NULL);
17979
17980   priv = self->priv;
17981
17982   box->x1 = 0.f;
17983   box->y1 = 0.f;
17984   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17985   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17986
17987   if (priv->content_box_valid)
17988     {
17989       *box = priv->content_box;
17990       return;
17991     }
17992
17993   /* no need to do any more work */
17994   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17995     return;
17996
17997   if (priv->content == NULL)
17998     return;
17999
18000   /* if the content does not have a preferred size then there is
18001    * no point in computing the content box
18002    */
18003   if (!clutter_content_get_preferred_size (priv->content,
18004                                            &content_w,
18005                                            &content_h))
18006     return;
18007
18008   alloc_w = box->x2;
18009   alloc_h = box->y2;
18010
18011   switch (priv->content_gravity)
18012     {
18013     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18014       box->x2 = box->x1 + MIN (content_w, alloc_w);
18015       box->y2 = box->y1 + MIN (content_h, alloc_h);
18016       break;
18017
18018     case CLUTTER_CONTENT_GRAVITY_TOP:
18019       if (alloc_w > content_w)
18020         {
18021           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18022           box->x2 = box->x1 + content_w;
18023         }
18024       box->y2 = box->y1 + MIN (content_h, alloc_h);
18025       break;
18026
18027     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18028       if (alloc_w > content_w)
18029         {
18030           box->x1 += (alloc_w - content_w);
18031           box->x2 = box->x1 + content_w;
18032         }
18033       box->y2 = box->y1 + MIN (content_h, alloc_h);
18034       break;
18035
18036     case CLUTTER_CONTENT_GRAVITY_LEFT:
18037       box->x2 = box->x1 + MIN (content_w, alloc_w);
18038       if (alloc_h > content_h)
18039         {
18040           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18041           box->y2 = box->y1 + content_h;
18042         }
18043       break;
18044
18045     case CLUTTER_CONTENT_GRAVITY_CENTER:
18046       if (alloc_w > content_w)
18047         {
18048           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18049           box->x2 = box->x1 + content_w;
18050         }
18051       if (alloc_h > content_h)
18052         {
18053           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18054           box->y2 = box->y1 + content_h;
18055         }
18056       break;
18057
18058     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18059       if (alloc_w > content_w)
18060         {
18061           box->x1 += (alloc_w - content_w);
18062           box->x2 = box->x1 + content_w;
18063         }
18064       if (alloc_h > content_h)
18065         {
18066           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18067           box->y2 = box->y1 + content_h;
18068         }
18069       break;
18070
18071     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18072       box->x2 = box->x1 + MIN (content_w, alloc_w);
18073       if (alloc_h > content_h)
18074         {
18075           box->y1 += (alloc_h - content_h);
18076           box->y2 = box->y1 + content_h;
18077         }
18078       break;
18079
18080     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18081       if (alloc_w > content_w)
18082         {
18083           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18084           box->x2 = box->x1 + content_w;
18085         }
18086       if (alloc_h > content_h)
18087         {
18088           box->y1 += (alloc_h - content_h);
18089           box->y2 = box->y1 + content_h;
18090         }
18091       break;
18092
18093     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18094       if (alloc_w > content_w)
18095         {
18096           box->x1 += (alloc_w - content_w);
18097           box->x2 = box->x1 + content_w;
18098         }
18099       if (alloc_h > content_h)
18100         {
18101           box->y1 += (alloc_h - content_h);
18102           box->y2 = box->y1 + content_h;
18103         }
18104       break;
18105
18106     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18107       g_assert_not_reached ();
18108       break;
18109
18110     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18111       {
18112         double r_c = content_w / content_h;
18113         double r_a = alloc_w / alloc_h;
18114
18115         if (r_c >= 1.0)
18116           {
18117             if (r_a >= 1.0)
18118               {
18119                 box->x1 = 0.f;
18120                 box->x2 = alloc_w;
18121
18122                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18123                 box->y2 = box->y1 + (alloc_w * r_c);
18124               }
18125             else
18126               {
18127                 box->y1 = 0.f;
18128                 box->y2 = alloc_h;
18129
18130                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18131                 box->x2 = box->x1 + (alloc_h * r_c);
18132               }
18133           }
18134         else
18135           {
18136             if (r_a >= 1.0)
18137               {
18138                 box->y1 = 0.f;
18139                 box->y2 = alloc_h;
18140
18141                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18142                 box->x2 = box->x1 + (alloc_h * r_c);
18143               }
18144             else
18145               {
18146                 box->x1 = 0.f;
18147                 box->x2 = alloc_w;
18148
18149                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18150                 box->y2 = box->y1 + (alloc_w * r_c);
18151               }
18152           }
18153       }
18154       break;
18155     }
18156 }
18157
18158 /**
18159  * clutter_actor_set_content_scaling_filters:
18160  * @self: a #ClutterActor
18161  * @min_filter: the minification filter for the content
18162  * @mag_filter: the magnification filter for the content
18163  *
18164  * Sets the minification and magnification filter to be applied when
18165  * scaling the #ClutterActor:content of a #ClutterActor.
18166  *
18167  * The #ClutterActor:minification-filter will be used when reducing
18168  * the size of the content; the #ClutterActor:magnification-filter
18169  * will be used when increasing the size of the content.
18170  *
18171  * Since: 1.10
18172  */
18173 void
18174 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18175                                            ClutterScalingFilter  min_filter,
18176                                            ClutterScalingFilter  mag_filter)
18177 {
18178   ClutterActorPrivate *priv;
18179   gboolean changed;
18180   GObject *obj;
18181
18182   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18183
18184   priv = self->priv;
18185   obj = G_OBJECT (self);
18186
18187   g_object_freeze_notify (obj);
18188
18189   changed = FALSE;
18190
18191   if (priv->min_filter != min_filter)
18192     {
18193       priv->min_filter = min_filter;
18194       changed = TRUE;
18195
18196       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18197     }
18198
18199   if (priv->mag_filter != mag_filter)
18200     {
18201       priv->mag_filter = mag_filter;
18202       changed = TRUE;
18203
18204       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18205     }
18206
18207   if (changed)
18208     clutter_actor_queue_redraw (self);
18209
18210   g_object_thaw_notify (obj);
18211 }
18212
18213 /**
18214  * clutter_actor_get_content_scaling_filters:
18215  * @self: a #ClutterActor
18216  * @min_filter: (out) (allow-none): return location for the minification
18217  *   filter, or %NULL
18218  * @mag_filter: (out) (allow-none): return location for the magnification
18219  *   filter, or %NULL
18220  *
18221  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18222  *
18223  * Since: 1.10
18224  */
18225 void
18226 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18227                                            ClutterScalingFilter *min_filter,
18228                                            ClutterScalingFilter *mag_filter)
18229 {
18230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18231
18232   if (min_filter != NULL)
18233     *min_filter = self->priv->min_filter;
18234
18235   if (mag_filter != NULL)
18236     *mag_filter = self->priv->mag_filter;
18237 }
18238
18239 /*
18240  * clutter_actor_queue_compute_expand:
18241  * @self: a #ClutterActor
18242  *
18243  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18244  * and its parents up to the top-level actor.
18245  *
18246  * This function also queues a relayout if anything changed.
18247  */
18248 static inline void
18249 clutter_actor_queue_compute_expand (ClutterActor *self)
18250 {
18251   ClutterActor *parent;
18252   gboolean changed;
18253
18254   if (self->priv->needs_compute_expand)
18255     return;
18256
18257   changed = FALSE;
18258   parent = self;
18259   while (parent != NULL)
18260     {
18261       if (!parent->priv->needs_compute_expand)
18262         {
18263           parent->priv->needs_compute_expand = TRUE;
18264           changed = TRUE;
18265         }
18266
18267       parent = parent->priv->parent;
18268     }
18269
18270   if (changed)
18271     clutter_actor_queue_relayout (self);
18272 }
18273
18274 /**
18275  * clutter_actor_set_x_expand:
18276  * @self: a #ClutterActor
18277  * @expand: whether the actor should expand horizontally
18278  *
18279  * Sets whether a #ClutterActor should expand horizontally; this means
18280  * that layout manager should allocate extra space for the actor, if
18281  * possible.
18282  *
18283  * Setting an actor to expand will also make all its parent expand, so
18284  * that it's possible to build an actor tree and only set this flag on
18285  * its leaves and not on every single actor.
18286  *
18287  * Since: 1.12
18288  */
18289 void
18290 clutter_actor_set_x_expand (ClutterActor *self,
18291                             gboolean      expand)
18292 {
18293   ClutterLayoutInfo *info;
18294
18295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18296
18297   expand = !!expand;
18298
18299   info = _clutter_actor_get_layout_info (self);
18300   if (info->x_expand != expand)
18301     {
18302       info->x_expand = expand;
18303
18304       self->priv->x_expand_set = TRUE;
18305
18306       clutter_actor_queue_compute_expand (self);
18307
18308       g_object_notify_by_pspec (G_OBJECT (self),
18309                                 obj_props[PROP_X_EXPAND]);
18310     }
18311 }
18312
18313 /**
18314  * clutter_actor_get_x_expand:
18315  * @self: a #ClutterActor
18316  *
18317  * Retrieves the value set with clutter_actor_set_x_expand().
18318  *
18319  * See also: clutter_actor_needs_expand()
18320  *
18321  * Return value: %TRUE if the actor has been set to expand
18322  *
18323  * Since: 1.12
18324  */
18325 gboolean
18326 clutter_actor_get_x_expand (ClutterActor *self)
18327 {
18328   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18329
18330   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18331 }
18332
18333 /**
18334  * clutter_actor_set_y_expand:
18335  * @self: a #ClutterActor
18336  * @expand: whether the actor should expand vertically
18337  *
18338  * Sets whether a #ClutterActor should expand horizontally; this means
18339  * that layout manager should allocate extra space for the actor, if
18340  * possible.
18341  *
18342  * Setting an actor to expand will also make all its parent expand, so
18343  * that it's possible to build an actor tree and only set this flag on
18344  * its leaves and not on every single actor.
18345  *
18346  * Since: 1.12
18347  */
18348 void
18349 clutter_actor_set_y_expand (ClutterActor *self,
18350                             gboolean      expand)
18351 {
18352   ClutterLayoutInfo *info;
18353
18354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18355
18356   expand = !!expand;
18357
18358   info = _clutter_actor_get_layout_info (self);
18359   if (info->y_expand != expand)
18360     {
18361       info->y_expand = expand;
18362
18363       self->priv->y_expand_set = TRUE;
18364
18365       clutter_actor_queue_compute_expand (self);
18366
18367       g_object_notify_by_pspec (G_OBJECT (self),
18368                                 obj_props[PROP_Y_EXPAND]);
18369     }
18370 }
18371
18372 /**
18373  * clutter_actor_get_y_expand:
18374  * @self: a #ClutterActor
18375  *
18376  * Retrieves the value set with clutter_actor_set_y_expand().
18377  *
18378  * See also: clutter_actor_needs_expand()
18379  *
18380  * Return value: %TRUE if the actor has been set to expand
18381  *
18382  * Since: 1.12
18383  */
18384 gboolean
18385 clutter_actor_get_y_expand (ClutterActor *self)
18386 {
18387   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18388
18389   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18390 }
18391
18392 static void
18393 clutter_actor_compute_expand_recursive (ClutterActor *self,
18394                                         gboolean     *x_expand_p,
18395                                         gboolean     *y_expand_p)
18396 {
18397   ClutterActorIter iter;
18398   ClutterActor *child;
18399   gboolean x_expand, y_expand;
18400
18401   x_expand = y_expand = FALSE;
18402
18403   /* note that we don't recurse into children if we're already set to expand;
18404    * this avoids traversing the whole actor tree, even if it may lead to some
18405    * child left with the needs_compute_expand flag set.
18406    */
18407   clutter_actor_iter_init (&iter, self);
18408   while (clutter_actor_iter_next (&iter, &child))
18409     {
18410       x_expand = x_expand ||
18411         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18412
18413       y_expand = y_expand ||
18414         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18415     }
18416
18417   *x_expand_p = x_expand;
18418   *y_expand_p = y_expand;
18419 }
18420
18421 static void
18422 clutter_actor_compute_expand (ClutterActor *self)
18423 {
18424   if (self->priv->needs_compute_expand)
18425     {
18426       const ClutterLayoutInfo *info;
18427       gboolean x_expand, y_expand;
18428
18429       info = _clutter_actor_get_layout_info_or_defaults (self);
18430
18431       if (self->priv->x_expand_set)
18432         x_expand = info->x_expand;
18433       else
18434         x_expand = FALSE;
18435
18436       if (self->priv->y_expand_set)
18437         y_expand = info->y_expand;
18438       else
18439         y_expand = FALSE;
18440
18441       /* we don't need to recurse down to the children if the
18442        * actor has been forcibly set to expand
18443        */
18444       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18445         {
18446           if (self->priv->n_children != 0)
18447             {
18448               gboolean *x_expand_p, *y_expand_p;
18449               gboolean ignored = FALSE;
18450
18451               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18452               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18453
18454               clutter_actor_compute_expand_recursive (self,
18455                                                       x_expand_p,
18456                                                       y_expand_p);
18457             }
18458         }
18459
18460       self->priv->needs_compute_expand = FALSE;
18461       self->priv->needs_x_expand = (x_expand != FALSE);
18462       self->priv->needs_y_expand = (y_expand != FALSE);
18463     }
18464 }
18465
18466 /**
18467  * clutter_actor_needs_expand:
18468  * @self: a #ClutterActor
18469  * @orientation: the direction of expansion
18470  *
18471  * Checks whether an actor, or any of its children, is set to expand
18472  * horizontally or vertically.
18473  *
18474  * This function should only be called by layout managers that can
18475  * assign extra space to their children.
18476  *
18477  * If you want to know whether the actor was explicitly set to expand,
18478  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18479  *
18480  * Return value: %TRUE if the actor should expand
18481  *
18482  * Since: 1.12
18483  */
18484 gboolean
18485 clutter_actor_needs_expand (ClutterActor       *self,
18486                             ClutterOrientation  orientation)
18487 {
18488   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18489
18490   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18491     return FALSE;
18492
18493   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18494     return FALSE;
18495
18496   clutter_actor_compute_expand (self);
18497
18498   switch (orientation)
18499     {
18500     case CLUTTER_ORIENTATION_HORIZONTAL:
18501       return self->priv->needs_x_expand;
18502
18503     case CLUTTER_ORIENTATION_VERTICAL:
18504       return self->priv->needs_y_expand;
18505     }
18506
18507   return FALSE;
18508 }