actor: Add basic automatic expand 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 flags_changed;
2277   gboolean retval;
2278   ClutterActorBox old_alloc = { 0, };
2279
2280   obj = G_OBJECT (self);
2281
2282   g_object_freeze_notify (obj);
2283
2284   clutter_actor_store_old_geometry (self, &old_alloc);
2285
2286   x1_changed = priv->allocation.x1 != box->x1;
2287   y1_changed = priv->allocation.y1 != box->y1;
2288   x2_changed = priv->allocation.x2 != box->x2;
2289   y2_changed = priv->allocation.y2 != box->y2;
2290
2291   flags_changed = priv->allocation_flags != flags;
2292
2293   priv->allocation = *box;
2294   priv->allocation_flags = flags;
2295
2296   /* allocation is authoritative */
2297   priv->needs_width_request = FALSE;
2298   priv->needs_height_request = FALSE;
2299   priv->needs_allocation = FALSE;
2300
2301   if (x1_changed || y1_changed ||
2302       x2_changed || y2_changed ||
2303       flags_changed)
2304     {
2305       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2306                     _clutter_actor_get_debug_name (self));
2307
2308       priv->transform_valid = FALSE;
2309
2310       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2311
2312       /* if the allocation changes, so does the content box */
2313       if (priv->content != NULL)
2314         {
2315           priv->content_box_valid = FALSE;
2316           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2317         }
2318
2319       retval = TRUE;
2320     }
2321   else
2322     retval = FALSE;
2323
2324   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2325
2326   g_object_thaw_notify (obj);
2327
2328   return retval;
2329 }
2330
2331 static void clutter_actor_real_allocate (ClutterActor           *self,
2332                                          const ClutterActorBox  *box,
2333                                          ClutterAllocationFlags  flags);
2334
2335 static inline void
2336 clutter_actor_maybe_layout_children (ClutterActor           *self,
2337                                      const ClutterActorBox  *allocation,
2338                                      ClutterAllocationFlags  flags)
2339 {
2340   ClutterActorPrivate *priv = self->priv;
2341
2342   /* this is going to be a bit hard to follow, so let's put an explanation
2343    * here.
2344    *
2345    * we want ClutterActor to have a default layout manager if the actor was
2346    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2347    *
2348    * we also want any subclass of ClutterActor that does not override the
2349    * ::allocate() virtual function to delegate to a layout manager.
2350    *
2351    * finally, we want to allow people subclassing ClutterActor and overriding
2352    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2353    *
2354    * on the other hand, we want existing actor subclasses overriding the
2355    * ::allocate() virtual function and chaining up to the parent's
2356    * implementation to continue working without allocating their children
2357    * twice, or without entering an allocation loop.
2358    *
2359    * for the first two points, we check if the class of the actor is
2360    * overridding the ::allocate() virtual function; if it isn't, then we
2361    * follow through with checking whether we have children and a layout
2362    * manager, and eventually calling clutter_layout_manager_allocate().
2363    *
2364    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2365    * allocation flags that we got passed, and if it is present, we continue
2366    * with the check above.
2367    *
2368    * if neither of these two checks yields a positive result, we just
2369    * assume that the ::allocate() virtual function that resulted in this
2370    * function being called will also allocate the children of the actor.
2371    */
2372
2373   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2374     goto check_layout;
2375
2376   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2377     goto check_layout;
2378
2379   return;
2380
2381 check_layout:
2382   if (priv->n_children != 0 &&
2383       priv->layout_manager != NULL)
2384     {
2385       ClutterContainer *container = CLUTTER_CONTAINER (self);
2386       ClutterAllocationFlags children_flags;
2387       ClutterActorBox children_box;
2388
2389       /* normalize the box passed to the layout manager */
2390       children_box.x1 = children_box.y1 = 0.f;
2391       children_box.x2 = (allocation->x2 - allocation->x1);
2392       children_box.y2 = (allocation->y2 - allocation->y1);
2393
2394       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2395        * the actor's children, since it refers only to the current
2396        * actor's allocation.
2397        */
2398       children_flags = flags;
2399       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2400
2401       CLUTTER_NOTE (LAYOUT,
2402                     "Allocating %d children of %s "
2403                     "at { %.2f, %.2f - %.2f x %.2f } "
2404                     "using %s",
2405                     priv->n_children,
2406                     _clutter_actor_get_debug_name (self),
2407                     allocation->x1,
2408                     allocation->y1,
2409                     (allocation->x2 - allocation->x1),
2410                     (allocation->y2 - allocation->y1),
2411                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2412
2413       clutter_layout_manager_allocate (priv->layout_manager,
2414                                        container,
2415                                        &children_box,
2416                                        children_flags);
2417     }
2418 }
2419
2420 static void
2421 clutter_actor_real_allocate (ClutterActor           *self,
2422                              const ClutterActorBox  *box,
2423                              ClutterAllocationFlags  flags)
2424 {
2425   ClutterActorPrivate *priv = self->priv;
2426   gboolean changed;
2427
2428   g_object_freeze_notify (G_OBJECT (self));
2429
2430   changed = clutter_actor_set_allocation_internal (self, box, flags);
2431
2432   /* we allocate our children before we notify changes in our geometry,
2433    * so that people connecting to properties will be able to get valid
2434    * data out of the sub-tree of the scene graph that has this actor at
2435    * the root.
2436    */
2437   clutter_actor_maybe_layout_children (self, box, flags);
2438
2439   if (changed)
2440     {
2441       ClutterActorBox signal_box = priv->allocation;
2442       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2443
2444       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2445                      &signal_box,
2446                      signal_flags);
2447     }
2448
2449   g_object_thaw_notify (G_OBJECT (self));
2450 }
2451
2452 static void
2453 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2454                                     ClutterActor *origin)
2455 {
2456   /* no point in queuing a redraw on a destroyed actor */
2457   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2458     return;
2459
2460   /* NB: We can't bail out early here if the actor is hidden in case
2461    * the actor bas been cloned. In this case the clone will need to
2462    * receive the signal so it can queue its own redraw.
2463    */
2464
2465   /* calls klass->queue_redraw in default handler */
2466   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2467 }
2468
2469 static void
2470 clutter_actor_real_queue_redraw (ClutterActor *self,
2471                                  ClutterActor *origin)
2472 {
2473   ClutterActor *parent;
2474
2475   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2476                 _clutter_actor_get_debug_name (self),
2477                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2478                                : "same actor");
2479
2480   /* no point in queuing a redraw on a destroyed actor */
2481   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2482     return;
2483
2484   /* If the queue redraw is coming from a child then the actor has
2485      become dirty and any queued effect is no longer valid */
2486   if (self != origin)
2487     {
2488       self->priv->is_dirty = TRUE;
2489       self->priv->effect_to_redraw = NULL;
2490     }
2491
2492   /* If the actor isn't visible, we still had to emit the signal
2493    * to allow for a ClutterClone, but the appearance of the parent
2494    * won't change so we don't have to propagate up the hierarchy.
2495    */
2496   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2497     return;
2498
2499   /* Although we could determine here that a full stage redraw
2500    * has already been queued and immediately bail out, we actually
2501    * guarantee that we will propagate a queue-redraw signal to our
2502    * parent at least once so that it's possible to implement a
2503    * container that tracks which of its children have queued a
2504    * redraw.
2505    */
2506   if (self->priv->propagated_one_redraw)
2507     {
2508       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2509       if (stage != NULL &&
2510           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2511         return;
2512     }
2513
2514   self->priv->propagated_one_redraw = TRUE;
2515
2516   /* notify parents, if they are all visible eventually we'll
2517    * queue redraw on the stage, which queues the redraw idle.
2518    */
2519   parent = clutter_actor_get_parent (self);
2520   if (parent != NULL)
2521     {
2522       /* this will go up recursively */
2523       _clutter_actor_signal_queue_redraw (parent, origin);
2524     }
2525 }
2526
2527 static void
2528 clutter_actor_real_queue_relayout (ClutterActor *self)
2529 {
2530   ClutterActorPrivate *priv = self->priv;
2531
2532   /* no point in queueing a redraw on a destroyed actor */
2533   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2534     return;
2535
2536   priv->needs_width_request  = TRUE;
2537   priv->needs_height_request = TRUE;
2538   priv->needs_allocation     = TRUE;
2539
2540   /* reset the cached size requests */
2541   memset (priv->width_requests, 0,
2542           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2543   memset (priv->height_requests, 0,
2544           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2545
2546   /* We need to go all the way up the hierarchy */
2547   if (priv->parent != NULL)
2548     _clutter_actor_queue_only_relayout (priv->parent);
2549 }
2550
2551 /**
2552  * clutter_actor_apply_relative_transform_to_point:
2553  * @self: A #ClutterActor
2554  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2555  *   default #ClutterStage
2556  * @point: A point as #ClutterVertex
2557  * @vertex: (out caller-allocates): The translated #ClutterVertex
2558  *
2559  * Transforms @point in coordinates relative to the actor into
2560  * ancestor-relative coordinates using the relevant transform
2561  * stack (i.e. scale, rotation, etc).
2562  *
2563  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2564  * this case, the coordinates returned will be the coordinates on
2565  * the stage before the projection is applied. This is different from
2566  * the behaviour of clutter_actor_apply_transform_to_point().
2567  *
2568  * Since: 0.6
2569  */
2570 void
2571 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2572                                                  ClutterActor        *ancestor,
2573                                                  const ClutterVertex *point,
2574                                                  ClutterVertex       *vertex)
2575 {
2576   gfloat w;
2577   CoglMatrix matrix;
2578
2579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2580   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2581   g_return_if_fail (point != NULL);
2582   g_return_if_fail (vertex != NULL);
2583
2584   *vertex = *point;
2585   w = 1.0;
2586
2587   if (ancestor == NULL)
2588     ancestor = _clutter_actor_get_stage_internal (self);
2589
2590   if (ancestor == NULL)
2591     {
2592       *vertex = *point;
2593       return;
2594     }
2595
2596   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2597   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2598 }
2599
2600 static gboolean
2601 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2602                                          const ClutterVertex *vertices_in,
2603                                          ClutterVertex *vertices_out,
2604                                          int n_vertices)
2605 {
2606   ClutterActor *stage;
2607   CoglMatrix modelview;
2608   CoglMatrix projection;
2609   float viewport[4];
2610
2611   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2612
2613   stage = _clutter_actor_get_stage_internal (self);
2614
2615   /* We really can't do anything meaningful in this case so don't try
2616    * to do any transform */
2617   if (stage == NULL)
2618     return FALSE;
2619
2620   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2621    * that gets us to stage coordinates, we want to go all the way to eye
2622    * coordinates */
2623   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2624
2625   /* Fetch the projection and viewport */
2626   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2627   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2628                                &viewport[0],
2629                                &viewport[1],
2630                                &viewport[2],
2631                                &viewport[3]);
2632
2633   _clutter_util_fully_transform_vertices (&modelview,
2634                                           &projection,
2635                                           viewport,
2636                                           vertices_in,
2637                                           vertices_out,
2638                                           n_vertices);
2639
2640   return TRUE;
2641 }
2642
2643 /**
2644  * clutter_actor_apply_transform_to_point:
2645  * @self: A #ClutterActor
2646  * @point: A point as #ClutterVertex
2647  * @vertex: (out caller-allocates): The translated #ClutterVertex
2648  *
2649  * Transforms @point in coordinates relative to the actor
2650  * into screen-relative coordinates with the current actor
2651  * transformation (i.e. scale, rotation, etc)
2652  *
2653  * Since: 0.4
2654  **/
2655 void
2656 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2657                                         const ClutterVertex *point,
2658                                         ClutterVertex       *vertex)
2659 {
2660   g_return_if_fail (point != NULL);
2661   g_return_if_fail (vertex != NULL);
2662   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2663 }
2664
2665 /*
2666  * _clutter_actor_get_relative_transformation_matrix:
2667  * @self: The actor whose coordinate space you want to transform from.
2668  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2669  *            or %NULL if you want to transform all the way to eye coordinates.
2670  * @matrix: A #CoglMatrix to store the transformation
2671  *
2672  * This gets a transformation @matrix that will transform coordinates from the
2673  * coordinate space of @self into the coordinate space of @ancestor.
2674  *
2675  * For example if you need a matrix that can transform the local actor
2676  * coordinates of @self into stage coordinates you would pass the actor's stage
2677  * pointer as the @ancestor.
2678  *
2679  * If you pass %NULL then the transformation will take you all the way through
2680  * to eye coordinates. This can be useful if you want to extract the entire
2681  * modelview transform that Clutter applies before applying the projection
2682  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2683  * using cogl_set_modelview_matrix() for example then you would want a matrix
2684  * that transforms into eye coordinates.
2685  *
2686  * <note><para>This function explicitly initializes the given @matrix. If you just
2687  * want clutter to multiply a relative transformation with an existing matrix
2688  * you can use clutter_actor_apply_relative_transformation_matrix()
2689  * instead.</para></note>
2690  *
2691  */
2692 /* XXX: We should consider caching the stage relative modelview along with
2693  * the actor itself */
2694 static void
2695 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2696                                                    ClutterActor *ancestor,
2697                                                    CoglMatrix *matrix)
2698 {
2699   cogl_matrix_init_identity (matrix);
2700
2701   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2702 }
2703
2704 /* Project the given @box into stage window coordinates, writing the
2705  * transformed vertices to @verts[]. */
2706 static gboolean
2707 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2708                                           const ClutterActorBox *box,
2709                                           ClutterVertex          verts[])
2710 {
2711   ClutterVertex box_vertices[4];
2712
2713   box_vertices[0].x = box->x1;
2714   box_vertices[0].y = box->y1;
2715   box_vertices[0].z = 0;
2716   box_vertices[1].x = box->x2;
2717   box_vertices[1].y = box->y1;
2718   box_vertices[1].z = 0;
2719   box_vertices[2].x = box->x1;
2720   box_vertices[2].y = box->y2;
2721   box_vertices[2].z = 0;
2722   box_vertices[3].x = box->x2;
2723   box_vertices[3].y = box->y2;
2724   box_vertices[3].z = 0;
2725
2726   return
2727     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2728 }
2729
2730 /**
2731  * clutter_actor_get_allocation_vertices:
2732  * @self: A #ClutterActor
2733  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2734  *   against, or %NULL to use the #ClutterStage
2735  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2736  *   location for an array of 4 #ClutterVertex in which to store the result
2737  *
2738  * Calculates the transformed coordinates of the four corners of the
2739  * actor in the plane of @ancestor. The returned vertices relate to
2740  * the #ClutterActorBox coordinates as follows:
2741  * <itemizedlist>
2742  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2743  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2744  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2745  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2746  * </itemizedlist>
2747  *
2748  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2749  * this case, the coordinates returned will be the coordinates on
2750  * the stage before the projection is applied. This is different from
2751  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2752  *
2753  * Since: 0.6
2754  */
2755 void
2756 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2757                                        ClutterActor  *ancestor,
2758                                        ClutterVertex  verts[])
2759 {
2760   ClutterActorPrivate *priv;
2761   ClutterActorBox box;
2762   ClutterVertex vertices[4];
2763   CoglMatrix modelview;
2764
2765   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2766   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2767
2768   if (ancestor == NULL)
2769     ancestor = _clutter_actor_get_stage_internal (self);
2770
2771   /* Fallback to a NOP transform if the actor isn't parented under a
2772    * stage. */
2773   if (ancestor == NULL)
2774     ancestor = self;
2775
2776   priv = self->priv;
2777
2778   /* if the actor needs to be allocated we force a relayout, so that
2779    * we will have valid values to use in the transformations */
2780   if (priv->needs_allocation)
2781     {
2782       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2783       if (stage)
2784         _clutter_stage_maybe_relayout (stage);
2785       else
2786         {
2787           box.x1 = box.y1 = 0;
2788           /* The result isn't really meaningful in this case but at
2789            * least try to do something *vaguely* reasonable... */
2790           clutter_actor_get_size (self, &box.x2, &box.y2);
2791         }
2792     }
2793
2794   clutter_actor_get_allocation_box (self, &box);
2795
2796   vertices[0].x = box.x1;
2797   vertices[0].y = box.y1;
2798   vertices[0].z = 0;
2799   vertices[1].x = box.x2;
2800   vertices[1].y = box.y1;
2801   vertices[1].z = 0;
2802   vertices[2].x = box.x1;
2803   vertices[2].y = box.y2;
2804   vertices[2].z = 0;
2805   vertices[3].x = box.x2;
2806   vertices[3].y = box.y2;
2807   vertices[3].z = 0;
2808
2809   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2810                                                      &modelview);
2811
2812   cogl_matrix_transform_points (&modelview,
2813                                 3,
2814                                 sizeof (ClutterVertex),
2815                                 vertices,
2816                                 sizeof (ClutterVertex),
2817                                 vertices,
2818                                 4);
2819 }
2820
2821 /**
2822  * clutter_actor_get_abs_allocation_vertices:
2823  * @self: A #ClutterActor
2824  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2825  *   of 4 #ClutterVertex where to store the result.
2826  *
2827  * Calculates the transformed screen coordinates of the four corners of
2828  * the actor; the returned vertices relate to the #ClutterActorBox
2829  * coordinates  as follows:
2830  * <itemizedlist>
2831  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2832  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2833  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2834  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2835  * </itemizedlist>
2836  *
2837  * Since: 0.4
2838  */
2839 void
2840 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2841                                            ClutterVertex  verts[])
2842 {
2843   ClutterActorPrivate *priv;
2844   ClutterActorBox actor_space_allocation;
2845
2846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2847
2848   priv = self->priv;
2849
2850   /* if the actor needs to be allocated we force a relayout, so that
2851    * the actor allocation box will be valid for
2852    * _clutter_actor_transform_and_project_box()
2853    */
2854   if (priv->needs_allocation)
2855     {
2856       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2857       /* There's nothing meaningful we can do now */
2858       if (!stage)
2859         return;
2860
2861       _clutter_stage_maybe_relayout (stage);
2862     }
2863
2864   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2865    * own coordinate space... */
2866   actor_space_allocation.x1 = 0;
2867   actor_space_allocation.y1 = 0;
2868   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2869   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2870   _clutter_actor_transform_and_project_box (self,
2871                                             &actor_space_allocation,
2872                                             verts);
2873 }
2874
2875 static void
2876 clutter_actor_real_apply_transform (ClutterActor *self,
2877                                     CoglMatrix   *matrix)
2878 {
2879   ClutterActorPrivate *priv = self->priv;
2880
2881   if (!priv->transform_valid)
2882     {
2883       CoglMatrix *transform = &priv->transform;
2884       const ClutterTransformInfo *info;
2885
2886       info = _clutter_actor_get_transform_info_or_defaults (self);
2887
2888       cogl_matrix_init_identity (transform);
2889
2890       cogl_matrix_translate (transform,
2891                              priv->allocation.x1,
2892                              priv->allocation.y1,
2893                              0.0);
2894
2895       if (info->depth)
2896         cogl_matrix_translate (transform, 0, 0, info->depth);
2897
2898       /*
2899        * because the rotation involves translations, we must scale
2900        * before applying the rotations (if we apply the scale after
2901        * the rotations, the translations included in the rotation are
2902        * not scaled and so the entire object will move on the screen
2903        * as a result of rotating it).
2904        */
2905       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2906         {
2907           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2908                                         &info->scale_center,
2909                                         cogl_matrix_scale (transform,
2910                                                            info->scale_x,
2911                                                            info->scale_y,
2912                                                            1.0));
2913         }
2914
2915       if (info->rz_angle)
2916         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2917                                       &info->rz_center,
2918                                       cogl_matrix_rotate (transform,
2919                                                           info->rz_angle,
2920                                                           0, 0, 1.0));
2921
2922       if (info->ry_angle)
2923         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2924                                       &info->ry_center,
2925                                       cogl_matrix_rotate (transform,
2926                                                           info->ry_angle,
2927                                                           0, 1.0, 0));
2928
2929       if (info->rx_angle)
2930         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2931                                       &info->rx_center,
2932                                       cogl_matrix_rotate (transform,
2933                                                           info->rx_angle,
2934                                                           1.0, 0, 0));
2935
2936       if (!clutter_anchor_coord_is_zero (&info->anchor))
2937         {
2938           gfloat x, y, z;
2939
2940           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2941           cogl_matrix_translate (transform, -x, -y, -z);
2942         }
2943
2944       priv->transform_valid = TRUE;
2945     }
2946
2947   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2948 }
2949
2950 /* Applies the transforms associated with this actor to the given
2951  * matrix. */
2952 void
2953 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2954                                           CoglMatrix *matrix)
2955 {
2956   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2957 }
2958
2959 /*
2960  * clutter_actor_apply_relative_transformation_matrix:
2961  * @self: The actor whose coordinate space you want to transform from.
2962  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2963  *            or %NULL if you want to transform all the way to eye coordinates.
2964  * @matrix: A #CoglMatrix to apply the transformation too.
2965  *
2966  * This multiplies a transform with @matrix that will transform coordinates
2967  * from the coordinate space of @self into the coordinate space of @ancestor.
2968  *
2969  * For example if you need a matrix that can transform the local actor
2970  * coordinates of @self into stage coordinates you would pass the actor's stage
2971  * pointer as the @ancestor.
2972  *
2973  * If you pass %NULL then the transformation will take you all the way through
2974  * to eye coordinates. This can be useful if you want to extract the entire
2975  * modelview transform that Clutter applies before applying the projection
2976  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2977  * using cogl_set_modelview_matrix() for example then you would want a matrix
2978  * that transforms into eye coordinates.
2979  *
2980  * <note>This function doesn't initialize the given @matrix, it simply
2981  * multiplies the requested transformation matrix with the existing contents of
2982  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2983  * before calling this function, or you can use
2984  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2985  */
2986 void
2987 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2988                                                      ClutterActor *ancestor,
2989                                                      CoglMatrix *matrix)
2990 {
2991   ClutterActor *parent;
2992
2993   /* Note we terminate before ever calling stage->apply_transform()
2994    * since that would conceptually be relative to the underlying
2995    * window OpenGL coordinates so we'd need a special @ancestor
2996    * value to represent the fake parent of the stage. */
2997   if (self == ancestor)
2998     return;
2999
3000   parent = clutter_actor_get_parent (self);
3001
3002   if (parent != NULL)
3003     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3004                                                          matrix);
3005
3006   _clutter_actor_apply_modelview_transform (self, matrix);
3007 }
3008
3009 static void
3010 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3011                                        ClutterPaintVolume *pv,
3012                                        const char *label,
3013                                        const CoglColor *color)
3014 {
3015   static CoglPipeline *outline = NULL;
3016   CoglPrimitive *prim;
3017   ClutterVertex line_ends[12 * 2];
3018   int n_vertices;
3019   CoglContext *ctx =
3020     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3021   /* XXX: at some point we'll query this from the stage but we can't
3022    * do that until the osx backend uses Cogl natively. */
3023   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3024
3025   if (outline == NULL)
3026     outline = cogl_pipeline_new (ctx);
3027
3028   _clutter_paint_volume_complete (pv);
3029
3030   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3031
3032   /* Front face */
3033   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3034   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3035   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3036   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3037
3038   if (!pv->is_2d)
3039     {
3040       /* Back face */
3041       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3042       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3043       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3044       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3045
3046       /* Lines connecting front face to back face */
3047       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3048       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3049       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3050       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3051     }
3052
3053   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3054                                 n_vertices,
3055                                 (CoglVertexP3 *)line_ends);
3056
3057   cogl_pipeline_set_color (outline, color);
3058   cogl_framebuffer_draw_primitive (fb, outline, prim);
3059   cogl_object_unref (prim);
3060
3061   if (label)
3062     {
3063       PangoLayout *layout;
3064       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3065       pango_layout_set_text (layout, label, -1);
3066       cogl_pango_render_layout (layout,
3067                                 pv->vertices[0].x,
3068                                 pv->vertices[0].y,
3069                                 color,
3070                                 0);
3071       g_object_unref (layout);
3072     }
3073 }
3074
3075 static void
3076 _clutter_actor_draw_paint_volume (ClutterActor *self)
3077 {
3078   ClutterPaintVolume *pv;
3079   CoglColor color;
3080
3081   pv = _clutter_actor_get_paint_volume_mutable (self);
3082   if (!pv)
3083     {
3084       gfloat width, height;
3085       ClutterPaintVolume fake_pv;
3086
3087       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3088       _clutter_paint_volume_init_static (&fake_pv, stage);
3089
3090       clutter_actor_get_size (self, &width, &height);
3091       clutter_paint_volume_set_width (&fake_pv, width);
3092       clutter_paint_volume_set_height (&fake_pv, height);
3093
3094       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3095       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3096                                              _clutter_actor_get_debug_name (self),
3097                                              &color);
3098
3099       clutter_paint_volume_free (&fake_pv);
3100     }
3101   else
3102     {
3103       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3104       _clutter_actor_draw_paint_volume_full (self, pv,
3105                                              _clutter_actor_get_debug_name (self),
3106                                              &color);
3107     }
3108 }
3109
3110 static void
3111 _clutter_actor_paint_cull_result (ClutterActor *self,
3112                                   gboolean success,
3113                                   ClutterCullResult result)
3114 {
3115   ClutterPaintVolume *pv;
3116   CoglColor color;
3117
3118   if (success)
3119     {
3120       if (result == CLUTTER_CULL_RESULT_IN)
3121         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3122       else if (result == CLUTTER_CULL_RESULT_OUT)
3123         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3124       else
3125         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3126     }
3127   else
3128     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3129
3130   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3131     _clutter_actor_draw_paint_volume_full (self, pv,
3132                                            _clutter_actor_get_debug_name (self),
3133                                            &color);
3134   else
3135     {
3136       PangoLayout *layout;
3137       char *label =
3138         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3139       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3140       cogl_set_source_color (&color);
3141
3142       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3143       pango_layout_set_text (layout, label, -1);
3144       cogl_pango_render_layout (layout,
3145                                 0,
3146                                 0,
3147                                 &color,
3148                                 0);
3149       g_free (label);
3150       g_object_unref (layout);
3151     }
3152 }
3153
3154 static int clone_paint_level = 0;
3155
3156 void
3157 _clutter_actor_push_clone_paint (void)
3158 {
3159   clone_paint_level++;
3160 }
3161
3162 void
3163 _clutter_actor_pop_clone_paint (void)
3164 {
3165   clone_paint_level--;
3166 }
3167
3168 static gboolean
3169 in_clone_paint (void)
3170 {
3171   return clone_paint_level > 0;
3172 }
3173
3174 /* Returns TRUE if the actor can be ignored */
3175 /* FIXME: we should return a ClutterCullResult, and
3176  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3177  * means there's no point in trying to cull descendants of the current
3178  * node. */
3179 static gboolean
3180 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3181 {
3182   ClutterActorPrivate *priv = self->priv;
3183   ClutterActor *stage;
3184   const ClutterPlane *stage_clip;
3185
3186   if (!priv->last_paint_volume_valid)
3187     {
3188       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3189                     "->last_paint_volume_valid == FALSE",
3190                     _clutter_actor_get_debug_name (self));
3191       return FALSE;
3192     }
3193
3194   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3195     return FALSE;
3196
3197   stage = _clutter_actor_get_stage_internal (self);
3198   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3199   if (G_UNLIKELY (!stage_clip))
3200     {
3201       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3202                     "No stage clip set",
3203                     _clutter_actor_get_debug_name (self));
3204       return FALSE;
3205     }
3206
3207   if (cogl_get_draw_framebuffer () !=
3208       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3209     {
3210       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3211                     "Current framebuffer doesn't correspond to stage",
3212                     _clutter_actor_get_debug_name (self));
3213       return FALSE;
3214     }
3215
3216   *result_out =
3217     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3218   return TRUE;
3219 }
3220
3221 static void
3222 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3223 {
3224   ClutterActorPrivate *priv = self->priv;
3225   const ClutterPaintVolume *pv;
3226
3227   if (priv->last_paint_volume_valid)
3228     {
3229       clutter_paint_volume_free (&priv->last_paint_volume);
3230       priv->last_paint_volume_valid = FALSE;
3231     }
3232
3233   pv = clutter_actor_get_paint_volume (self);
3234   if (!pv)
3235     {
3236       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3237                     "Actor failed to report a paint volume",
3238                     _clutter_actor_get_debug_name (self));
3239       return;
3240     }
3241
3242   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3243
3244   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3245                                             NULL); /* eye coordinates */
3246
3247   priv->last_paint_volume_valid = TRUE;
3248 }
3249
3250 static inline gboolean
3251 actor_has_shader_data (ClutterActor *self)
3252 {
3253   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3254 }
3255
3256 guint32
3257 _clutter_actor_get_pick_id (ClutterActor *self)
3258 {
3259   if (self->priv->pick_id < 0)
3260     return 0;
3261
3262   return self->priv->pick_id;
3263 }
3264
3265 /* This is the same as clutter_actor_add_effect except that it doesn't
3266    queue a redraw and it doesn't notify on the effect property */
3267 static void
3268 _clutter_actor_add_effect_internal (ClutterActor  *self,
3269                                     ClutterEffect *effect)
3270 {
3271   ClutterActorPrivate *priv = self->priv;
3272
3273   if (priv->effects == NULL)
3274     {
3275       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3276       priv->effects->actor = self;
3277     }
3278
3279   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3280 }
3281
3282 /* This is the same as clutter_actor_remove_effect except that it doesn't
3283    queue a redraw and it doesn't notify on the effect property */
3284 static void
3285 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3286                                        ClutterEffect *effect)
3287 {
3288   ClutterActorPrivate *priv = self->priv;
3289
3290   if (priv->effects == NULL)
3291     return;
3292
3293   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3294
3295   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3296     g_clear_object (&priv->effects);
3297 }
3298
3299 static gboolean
3300 needs_flatten_effect (ClutterActor *self)
3301 {
3302   ClutterActorPrivate *priv = self->priv;
3303
3304   if (G_UNLIKELY (clutter_paint_debug_flags &
3305                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3306     return FALSE;
3307
3308   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3309     return TRUE;
3310   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3311     {
3312       if (clutter_actor_get_paint_opacity (self) < 255 &&
3313           clutter_actor_has_overlaps (self))
3314         return TRUE;
3315     }
3316
3317   return FALSE;
3318 }
3319
3320 static void
3321 add_or_remove_flatten_effect (ClutterActor *self)
3322 {
3323   ClutterActorPrivate *priv = self->priv;
3324
3325   /* Add or remove the flatten effect depending on the
3326      offscreen-redirect property. */
3327   if (needs_flatten_effect (self))
3328     {
3329       if (priv->flatten_effect == NULL)
3330         {
3331           ClutterActorMeta *actor_meta;
3332           gint priority;
3333
3334           priv->flatten_effect = _clutter_flatten_effect_new ();
3335           /* Keep a reference to the effect so that we can queue
3336              redraws from it */
3337           g_object_ref_sink (priv->flatten_effect);
3338
3339           /* Set the priority of the effect to high so that it will
3340              always be applied to the actor first. It uses an internal
3341              priority so that it won't be visible to applications */
3342           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3343           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3344           _clutter_actor_meta_set_priority (actor_meta, priority);
3345
3346           /* This will add the effect without queueing a redraw */
3347           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3348         }
3349     }
3350   else
3351     {
3352       if (priv->flatten_effect != NULL)
3353         {
3354           /* Destroy the effect so that it will lose its fbo cache of
3355              the actor */
3356           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3357           g_clear_object (&priv->flatten_effect);
3358         }
3359     }
3360 }
3361
3362 static void
3363 clutter_actor_real_paint (ClutterActor *actor)
3364 {
3365   ClutterActorPrivate *priv = actor->priv;
3366   ClutterActor *iter;
3367
3368   for (iter = priv->first_child;
3369        iter != NULL;
3370        iter = iter->priv->next_sibling)
3371     {
3372       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3373                     _clutter_actor_get_debug_name (iter),
3374                     _clutter_actor_get_debug_name (actor),
3375                     iter->priv->allocation.x1,
3376                     iter->priv->allocation.y1,
3377                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3378                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3379
3380       clutter_actor_paint (iter);
3381     }
3382 }
3383
3384 static gboolean
3385 clutter_actor_paint_node (ClutterActor     *actor,
3386                           ClutterPaintNode *root)
3387 {
3388   ClutterActorPrivate *priv = actor->priv;
3389
3390   if (root == NULL)
3391     return FALSE;
3392
3393   if (priv->bg_color_set &&
3394       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3395     {
3396       ClutterPaintNode *node;
3397       ClutterColor bg_color;
3398       ClutterActorBox box;
3399
3400       box.x1 = 0.f;
3401       box.y1 = 0.f;
3402       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3403       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3404
3405       bg_color = priv->bg_color;
3406       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3407                      * priv->bg_color.alpha
3408                      / 255;
3409
3410       node = clutter_color_node_new (&bg_color);
3411       clutter_paint_node_set_name (node, "backgroundColor");
3412       clutter_paint_node_add_rectangle (node, &box);
3413       clutter_paint_node_add_child (root, node);
3414       clutter_paint_node_unref (node);
3415     }
3416
3417   if (priv->content != NULL)
3418     _clutter_content_paint_content (priv->content, actor, root);
3419
3420   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3421     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3422
3423   if (clutter_paint_node_get_n_children (root) == 0)
3424     return FALSE;
3425
3426 #ifdef CLUTTER_ENABLE_DEBUG
3427   if (CLUTTER_HAS_DEBUG (PAINT))
3428     {
3429       /* dump the tree only if we have one */
3430       _clutter_paint_node_dump_tree (root);
3431     }
3432 #endif /* CLUTTER_ENABLE_DEBUG */
3433
3434   _clutter_paint_node_paint (root);
3435
3436 #if 0
3437   /* XXX: Uncomment this when we disable emitting the paint signal */
3438   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3439 #endif
3440
3441   return TRUE;
3442 }
3443
3444 /**
3445  * clutter_actor_paint:
3446  * @self: A #ClutterActor
3447  *
3448  * Renders the actor to display.
3449  *
3450  * This function should not be called directly by applications.
3451  * Call clutter_actor_queue_redraw() to queue paints, instead.
3452  *
3453  * This function is context-aware, and will either cause a
3454  * regular paint or a pick paint.
3455  *
3456  * This function will emit the #ClutterActor::paint signal or
3457  * the #ClutterActor::pick signal, depending on the context.
3458  *
3459  * This function does not paint the actor if the actor is set to 0,
3460  * unless it is performing a pick paint.
3461  */
3462 void
3463 clutter_actor_paint (ClutterActor *self)
3464 {
3465   ClutterActorPrivate *priv;
3466   ClutterPickMode pick_mode;
3467   gboolean clip_set = FALSE;
3468   gboolean shader_applied = FALSE;
3469
3470   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3471                           "Actor real-paint counter",
3472                           "Increments each time any actor is painted",
3473                           0 /* no application private data */);
3474   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3475                           "Actor pick-paint counter",
3476                           "Increments each time any actor is painted "
3477                           "for picking",
3478                           0 /* no application private data */);
3479
3480   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3481
3482   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3483     return;
3484
3485   priv = self->priv;
3486
3487   pick_mode = _clutter_context_get_pick_mode ();
3488
3489   if (pick_mode == CLUTTER_PICK_NONE)
3490     priv->propagated_one_redraw = FALSE;
3491
3492   /* It's an important optimization that we consider painting of
3493    * actors with 0 opacity to be a NOP... */
3494   if (pick_mode == CLUTTER_PICK_NONE &&
3495       /* ignore top-levels, since they might be transparent */
3496       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3497       /* Use the override opacity if its been set */
3498       ((priv->opacity_override >= 0) ?
3499        priv->opacity_override : priv->opacity) == 0)
3500     return;
3501
3502   /* if we aren't paintable (not in a toplevel with all
3503    * parents paintable) then do nothing.
3504    */
3505   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3506     return;
3507
3508   /* mark that we are in the paint process */
3509   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3510
3511   cogl_push_matrix();
3512
3513   if (priv->enable_model_view_transform)
3514     {
3515       CoglMatrix matrix;
3516
3517       /* XXX: It could be better to cache the modelview with the actor
3518        * instead of progressively building up the transformations on
3519        * the matrix stack every time we paint. */
3520       cogl_get_modelview_matrix (&matrix);
3521       _clutter_actor_apply_modelview_transform (self, &matrix);
3522
3523 #ifdef CLUTTER_ENABLE_DEBUG
3524       /* Catch when out-of-band transforms have been made by actors not as part
3525        * of an apply_transform vfunc... */
3526       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3527         {
3528           CoglMatrix expected_matrix;
3529
3530           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3531                                                              &expected_matrix);
3532
3533           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3534             {
3535               GString *buf = g_string_sized_new (1024);
3536               ClutterActor *parent;
3537
3538               parent = self;
3539               while (parent != NULL)
3540                 {
3541                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3542
3543                   if (parent->priv->parent != NULL)
3544                     g_string_append (buf, "->");
3545
3546                   parent = parent->priv->parent;
3547                 }
3548
3549               g_warning ("Unexpected transform found when painting actor "
3550                          "\"%s\". This will be caused by one of the actor's "
3551                          "ancestors (%s) using the Cogl API directly to transform "
3552                          "children instead of using ::apply_transform().",
3553                          _clutter_actor_get_debug_name (self),
3554                          buf->str);
3555
3556               g_string_free (buf, TRUE);
3557             }
3558         }
3559 #endif /* CLUTTER_ENABLE_DEBUG */
3560
3561       cogl_set_modelview_matrix (&matrix);
3562     }
3563
3564   if (priv->has_clip)
3565     {
3566       cogl_clip_push_rectangle (priv->clip.x,
3567                                 priv->clip.y,
3568                                 priv->clip.x + priv->clip.width,
3569                                 priv->clip.y + priv->clip.height);
3570       clip_set = TRUE;
3571     }
3572   else if (priv->clip_to_allocation)
3573     {
3574       gfloat width, height;
3575
3576       width  = priv->allocation.x2 - priv->allocation.x1;
3577       height = priv->allocation.y2 - priv->allocation.y1;
3578
3579       cogl_clip_push_rectangle (0, 0, width, height);
3580       clip_set = TRUE;
3581     }
3582
3583   if (pick_mode == CLUTTER_PICK_NONE)
3584     {
3585       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3586
3587       /* We check whether we need to add the flatten effect before
3588          each paint so that we can avoid having a mechanism for
3589          applications to notify when the value of the
3590          has_overlaps virtual changes. */
3591       add_or_remove_flatten_effect (self);
3592     }
3593   else
3594     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3595
3596   /* We save the current paint volume so that the next time the
3597    * actor queues a redraw we can constrain the redraw to just
3598    * cover the union of the new bounding box and the old.
3599    *
3600    * We also fetch the current paint volume to perform culling so
3601    * we can avoid painting actors outside the current clip region.
3602    *
3603    * If we are painting inside a clone, we should neither update
3604    * the paint volume or use it to cull painting, since the paint
3605    * box represents the location of the source actor on the
3606    * screen.
3607    *
3608    * XXX: We are starting to do a lot of vertex transforms on
3609    * the CPU in a typical paint, so at some point we should
3610    * audit these and consider caching some things.
3611    *
3612    * NB: We don't perform culling while picking at this point because
3613    * clutter-stage.c doesn't setup the clipping planes appropriately.
3614    *
3615    * NB: We don't want to update the last-paint-volume during picking
3616    * because the last-paint-volume is used to determine the old screen
3617    * space location of an actor that has moved so we can know the
3618    * minimal region to redraw to clear an old view of the actor. If we
3619    * update this during picking then by the time we come around to
3620    * paint then the last-paint-volume would likely represent the new
3621    * actor position not the old.
3622    */
3623   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3624     {
3625       gboolean success;
3626       /* annoyingly gcc warns if uninitialized even though
3627        * the initialization is redundant :-( */
3628       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3629
3630       if (G_LIKELY ((clutter_paint_debug_flags &
3631                      (CLUTTER_DEBUG_DISABLE_CULLING |
3632                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3633                     (CLUTTER_DEBUG_DISABLE_CULLING |
3634                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3635         _clutter_actor_update_last_paint_volume (self);
3636
3637       success = cull_actor (self, &result);
3638
3639       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3640         _clutter_actor_paint_cull_result (self, success, result);
3641       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3642         goto done;
3643     }
3644
3645   if (priv->effects == NULL)
3646     {
3647       if (pick_mode == CLUTTER_PICK_NONE &&
3648           actor_has_shader_data (self))
3649         {
3650           _clutter_actor_shader_pre_paint (self, FALSE);
3651           shader_applied = TRUE;
3652         }
3653
3654       priv->next_effect_to_paint = NULL;
3655     }
3656   else
3657     priv->next_effect_to_paint =
3658       _clutter_meta_group_peek_metas (priv->effects);
3659
3660   clutter_actor_continue_paint (self);
3661
3662   if (shader_applied)
3663     _clutter_actor_shader_post_paint (self);
3664
3665   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3666                   pick_mode == CLUTTER_PICK_NONE))
3667     _clutter_actor_draw_paint_volume (self);
3668
3669 done:
3670   /* If we make it here then the actor has run through a complete
3671      paint run including all the effects so it's no longer dirty */
3672   if (pick_mode == CLUTTER_PICK_NONE)
3673     priv->is_dirty = FALSE;
3674
3675   if (clip_set)
3676     cogl_clip_pop();
3677
3678   cogl_pop_matrix();
3679
3680   /* paint sequence complete */
3681   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3682 }
3683
3684 /**
3685  * clutter_actor_continue_paint:
3686  * @self: A #ClutterActor
3687  *
3688  * Run the next stage of the paint sequence. This function should only
3689  * be called within the implementation of the ‘run’ virtual of a
3690  * #ClutterEffect. It will cause the run method of the next effect to
3691  * be applied, or it will paint the actual actor if the current effect
3692  * is the last effect in the chain.
3693  *
3694  * Since: 1.8
3695  */
3696 void
3697 clutter_actor_continue_paint (ClutterActor *self)
3698 {
3699   ClutterActorPrivate *priv;
3700
3701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3702   /* This should only be called from with in the ‘run’ implementation
3703      of a ClutterEffect */
3704   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3705
3706   priv = self->priv;
3707
3708   /* Skip any effects that are disabled */
3709   while (priv->next_effect_to_paint &&
3710          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3711     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3712
3713   /* If this has come from the last effect then we'll just paint the
3714      actual actor */
3715   if (priv->next_effect_to_paint == NULL)
3716     {
3717       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3718         {
3719           ClutterPaintNode *dummy;
3720
3721           /* XXX - this will go away in 2.0, when we can get rid of this
3722            * stuff and switch to a pure retained render tree of PaintNodes
3723            * for the entire frame, starting from the Stage; the paint()
3724            * virtual function can then be called directly.
3725            */
3726           dummy = _clutter_dummy_node_new (self);
3727           clutter_paint_node_set_name (dummy, "Root");
3728
3729           /* XXX - for 1.12, we use the return value of paint_node() to
3730            * decide whether we should emit the ::paint signal.
3731            */
3732           clutter_actor_paint_node (self, dummy);
3733           clutter_paint_node_unref (dummy);
3734
3735           g_signal_emit (self, actor_signals[PAINT], 0);
3736         }
3737       else
3738         {
3739           ClutterColor col = { 0, };
3740
3741           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3742
3743           /* Actor will then paint silhouette of itself in supplied
3744            * color.  See clutter_stage_get_actor_at_pos() for where
3745            * picking is enabled.
3746            */
3747           g_signal_emit (self, actor_signals[PICK], 0, &col);
3748         }
3749     }
3750   else
3751     {
3752       ClutterEffect *old_current_effect;
3753       ClutterEffectPaintFlags run_flags = 0;
3754
3755       /* Cache the current effect so that we can put it back before
3756          returning */
3757       old_current_effect = priv->current_effect;
3758
3759       priv->current_effect = priv->next_effect_to_paint->data;
3760       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3761
3762       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3763         {
3764           if (priv->is_dirty)
3765             {
3766               /* If there's an effect queued with this redraw then all
3767                  effects up to that one will be considered dirty. It
3768                  is expected the queued effect will paint the cached
3769                  image and not call clutter_actor_continue_paint again
3770                  (although it should work ok if it does) */
3771               if (priv->effect_to_redraw == NULL ||
3772                   priv->current_effect != priv->effect_to_redraw)
3773                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3774             }
3775
3776           _clutter_effect_paint (priv->current_effect, run_flags);
3777         }
3778       else
3779         {
3780           /* We can't determine when an actor has been modified since
3781              its last pick so lets just assume it has always been
3782              modified */
3783           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3784
3785           _clutter_effect_pick (priv->current_effect, run_flags);
3786         }
3787
3788       priv->current_effect = old_current_effect;
3789     }
3790 }
3791
3792 static ClutterActorTraverseVisitFlags
3793 invalidate_queue_redraw_entry (ClutterActor *self,
3794                                int           depth,
3795                                gpointer      user_data)
3796 {
3797   ClutterActorPrivate *priv = self->priv;
3798
3799   if (priv->queue_redraw_entry != NULL)
3800     {
3801       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3802       priv->queue_redraw_entry = NULL;
3803     }
3804
3805   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3806 }
3807
3808 static inline void
3809 remove_child (ClutterActor *self,
3810               ClutterActor *child)
3811 {
3812   ClutterActor *prev_sibling, *next_sibling;
3813
3814   prev_sibling = child->priv->prev_sibling;
3815   next_sibling = child->priv->next_sibling;
3816
3817   if (prev_sibling != NULL)
3818     prev_sibling->priv->next_sibling = next_sibling;
3819
3820   if (next_sibling != NULL)
3821     next_sibling->priv->prev_sibling = prev_sibling;
3822
3823   if (self->priv->first_child == child)
3824     self->priv->first_child = next_sibling;
3825
3826   if (self->priv->last_child == child)
3827     self->priv->last_child = prev_sibling;
3828
3829   child->priv->parent = NULL;
3830   child->priv->prev_sibling = NULL;
3831   child->priv->next_sibling = NULL;
3832 }
3833
3834 typedef enum {
3835   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3836   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3837   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3838   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3839   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3840   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3841
3842   /* default flags for public API */
3843   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3844                                     REMOVE_CHILD_EMIT_PARENT_SET |
3845                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3846                                     REMOVE_CHILD_CHECK_STATE |
3847                                     REMOVE_CHILD_FLUSH_QUEUE |
3848                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3849
3850   /* flags for legacy/deprecated API */
3851   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3852                                     REMOVE_CHILD_FLUSH_QUEUE |
3853                                     REMOVE_CHILD_EMIT_PARENT_SET |
3854                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3855 } ClutterActorRemoveChildFlags;
3856
3857 /*< private >
3858  * clutter_actor_remove_child_internal:
3859  * @self: a #ClutterActor
3860  * @child: the child of @self that has to be removed
3861  * @flags: control the removal operations
3862  *
3863  * Removes @child from the list of children of @self.
3864  */
3865 static void
3866 clutter_actor_remove_child_internal (ClutterActor                 *self,
3867                                      ClutterActor                 *child,
3868                                      ClutterActorRemoveChildFlags  flags)
3869 {
3870   ClutterActor *old_first, *old_last;
3871   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3872   gboolean flush_queue;
3873   gboolean notify_first_last;
3874   gboolean was_mapped;
3875
3876   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3877   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3878   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3879   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3880   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3881   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3882
3883   g_object_freeze_notify (G_OBJECT (self));
3884
3885   if (destroy_meta)
3886     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3887
3888   if (check_state)
3889     {
3890       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3891
3892       /* we need to unrealize *before* we set parent_actor to NULL,
3893        * because in an unrealize method actors are dissociating from the
3894        * stage, which means they need to be able to
3895        * clutter_actor_get_stage().
3896        *
3897        * yhis should unmap and unrealize, unless we're reparenting.
3898        */
3899       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3900     }
3901   else
3902     was_mapped = FALSE;
3903
3904   if (flush_queue)
3905     {
3906       /* We take this opportunity to invalidate any queue redraw entry
3907        * associated with the actor and descendants since we won't be able to
3908        * determine the appropriate stage after this.
3909        *
3910        * we do this after we updated the mapped state because actors might
3911        * end up queueing redraws inside their mapped/unmapped virtual
3912        * functions, and if we invalidate the redraw entry we could end up
3913        * with an inconsistent state and weird memory corruption. see
3914        * bugs:
3915        *
3916        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3917        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3918        */
3919       _clutter_actor_traverse (child,
3920                                0,
3921                                invalidate_queue_redraw_entry,
3922                                NULL,
3923                                NULL);
3924     }
3925
3926   old_first = self->priv->first_child;
3927   old_last = self->priv->last_child;
3928
3929   remove_child (self, child);
3930
3931   self->priv->n_children -= 1;
3932
3933   self->priv->age += 1;
3934
3935   /* if the child that got removed was visible and set to
3936    * expand then we want to reset the parent's state in
3937    * case the child was the only thing that was making it
3938    * expand.
3939    */
3940   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3941       (child->priv->needs_compute_expand ||
3942        child->priv->needs_x_expand ||
3943        child->priv->needs_y_expand))
3944     {
3945       clutter_actor_queue_compute_expand (self);
3946     }
3947
3948   /* clutter_actor_reparent() will emit ::parent-set for us */
3949   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3950     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3951
3952   /* if the child was mapped then we need to relayout ourselves to account
3953    * for the removed child
3954    */
3955   if (was_mapped)
3956     clutter_actor_queue_relayout (self);
3957
3958   /* we need to emit the signal before dropping the reference */
3959   if (emit_actor_removed)
3960     g_signal_emit_by_name (self, "actor-removed", child);
3961
3962   if (notify_first_last)
3963     {
3964       if (old_first != self->priv->first_child)
3965         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3966
3967       if (old_last != self->priv->last_child)
3968         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3969     }
3970
3971   g_object_thaw_notify (G_OBJECT (self));
3972
3973   /* remove the reference we acquired in clutter_actor_add_child() */
3974   g_object_unref (child);
3975 }
3976
3977 static const ClutterTransformInfo default_transform_info = {
3978   0.0, { 0, },          /* rotation-x */
3979   0.0, { 0, },          /* rotation-y */
3980   0.0, { 0, },          /* rotation-z */
3981
3982   1.0, 1.0, { 0, },     /* scale */
3983
3984   { 0, },               /* anchor */
3985
3986   0.0,                  /* depth */
3987 };
3988
3989 /*< private >
3990  * _clutter_actor_get_transform_info_or_defaults:
3991  * @self: a #ClutterActor
3992  *
3993  * Retrieves the ClutterTransformInfo structure associated to an actor.
3994  *
3995  * If the actor does not have a ClutterTransformInfo structure associated
3996  * to it, then the default structure will be returned.
3997  *
3998  * This function should only be used for getters.
3999  *
4000  * Return value: a const pointer to the ClutterTransformInfo structure
4001  */
4002 const ClutterTransformInfo *
4003 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4004 {
4005   ClutterTransformInfo *info;
4006
4007   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4008   if (info != NULL)
4009     return info;
4010
4011   return &default_transform_info;
4012 }
4013
4014 static void
4015 clutter_transform_info_free (gpointer data)
4016 {
4017   if (data != NULL)
4018     g_slice_free (ClutterTransformInfo, data);
4019 }
4020
4021 /*< private >
4022  * _clutter_actor_get_transform_info:
4023  * @self: a #ClutterActor
4024  *
4025  * Retrieves a pointer to the ClutterTransformInfo structure.
4026  *
4027  * If the actor does not have a ClutterTransformInfo associated to it, one
4028  * will be created and initialized to the default values.
4029  *
4030  * This function should be used for setters.
4031  *
4032  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4033  * instead.
4034  *
4035  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4036  *   structure
4037  */
4038 ClutterTransformInfo *
4039 _clutter_actor_get_transform_info (ClutterActor *self)
4040 {
4041   ClutterTransformInfo *info;
4042
4043   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4044   if (info == NULL)
4045     {
4046       info = g_slice_new (ClutterTransformInfo);
4047
4048       *info = default_transform_info;
4049
4050       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4051                                info,
4052                                clutter_transform_info_free);
4053     }
4054
4055   return info;
4056 }
4057
4058 /*< private >
4059  * clutter_actor_set_rotation_angle_internal:
4060  * @self: a #ClutterActor
4061  * @axis: the axis of the angle to change
4062  * @angle: the angle of rotation
4063  *
4064  * Sets the rotation angle on the given axis without affecting the
4065  * rotation center point.
4066  */
4067 static inline void
4068 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4069                                            ClutterRotateAxis  axis,
4070                                            gdouble            angle)
4071 {
4072   GObject *obj = G_OBJECT (self);
4073   ClutterTransformInfo *info;
4074
4075   info = _clutter_actor_get_transform_info (self);
4076
4077   g_object_freeze_notify (obj);
4078
4079   switch (axis)
4080     {
4081     case CLUTTER_X_AXIS:
4082       info->rx_angle = angle;
4083       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4084       break;
4085
4086     case CLUTTER_Y_AXIS:
4087       info->ry_angle = angle;
4088       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4089       break;
4090
4091     case CLUTTER_Z_AXIS:
4092       info->rz_angle = angle;
4093       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4094       break;
4095     }
4096
4097   self->priv->transform_valid = FALSE;
4098
4099   g_object_thaw_notify (obj);
4100
4101   clutter_actor_queue_redraw (self);
4102 }
4103
4104 static inline void
4105 clutter_actor_set_rotation_angle (ClutterActor      *self,
4106                                   ClutterRotateAxis  axis,
4107                                   gdouble            angle)
4108 {
4109   const ClutterTransformInfo *info;
4110   const double *cur_angle_p = NULL;
4111   GParamSpec *pspec = NULL;
4112
4113   info = _clutter_actor_get_transform_info_or_defaults (self);
4114
4115   switch (axis)
4116     {
4117     case CLUTTER_X_AXIS:
4118       cur_angle_p = &info->rx_angle;
4119       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4120       break;
4121
4122     case CLUTTER_Y_AXIS:
4123       cur_angle_p = &info->ry_angle;
4124       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4125       break;
4126
4127     case CLUTTER_Z_AXIS:
4128       cur_angle_p = &info->rz_angle;
4129       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4130       break;
4131     }
4132
4133   g_assert (pspec != NULL);
4134   g_assert (cur_angle_p != NULL);
4135
4136   if (_clutter_actor_get_transition (self, pspec) == NULL)
4137     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4138   else
4139     _clutter_actor_update_transition (self, pspec, angle);
4140
4141   clutter_actor_queue_redraw (self);
4142 }
4143
4144 /*< private >
4145  * clutter_actor_set_rotation_center_internal:
4146  * @self: a #ClutterActor
4147  * @axis: the axis of the center to change
4148  * @center: the coordinates of the rotation center
4149  *
4150  * Sets the rotation center on the given axis without affecting the
4151  * rotation angle.
4152  */
4153 static inline void
4154 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4155                                             ClutterRotateAxis    axis,
4156                                             const ClutterVertex *center)
4157 {
4158   GObject *obj = G_OBJECT (self);
4159   ClutterTransformInfo *info;
4160   ClutterVertex v = { 0, 0, 0 };
4161
4162   info = _clutter_actor_get_transform_info (self);
4163
4164   if (center != NULL)
4165     v = *center;
4166
4167   g_object_freeze_notify (obj);
4168
4169   switch (axis)
4170     {
4171     case CLUTTER_X_AXIS:
4172       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4173       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4174       break;
4175
4176     case CLUTTER_Y_AXIS:
4177       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4178       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4179       break;
4180
4181     case CLUTTER_Z_AXIS:
4182       /* if the previously set rotation center was fractional, then
4183        * setting explicit coordinates will have to notify the
4184        * :rotation-center-z-gravity property as well
4185        */
4186       if (info->rz_center.is_fractional)
4187         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4188
4189       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4190       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4191       break;
4192     }
4193
4194   self->priv->transform_valid = FALSE;
4195
4196   g_object_thaw_notify (obj);
4197
4198   clutter_actor_queue_redraw (self);
4199 }
4200
4201 static void
4202 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4203                                          double factor,
4204                                          GParamSpec *pspec)
4205 {
4206   GObject *obj = G_OBJECT (self);
4207   ClutterTransformInfo *info;
4208
4209   info = _clutter_actor_get_transform_info (self);
4210
4211   if (pspec == obj_props[PROP_SCALE_X])
4212     info->scale_x = factor;
4213   else
4214     info->scale_y = factor;
4215
4216   self->priv->transform_valid = FALSE;
4217   clutter_actor_queue_redraw (self);
4218   g_object_notify_by_pspec (obj, pspec);
4219 }
4220
4221 static inline void
4222 clutter_actor_set_scale_factor (ClutterActor      *self,
4223                                 ClutterRotateAxis  axis,
4224                                 gdouble            factor)
4225 {
4226   const ClutterTransformInfo *info;
4227   const double *scale_p = NULL;
4228   GParamSpec *pspec = NULL;
4229
4230   info = _clutter_actor_get_transform_info_or_defaults (self);
4231
4232   switch (axis)
4233     {
4234     case CLUTTER_X_AXIS:
4235       pspec = obj_props[PROP_SCALE_X];
4236       scale_p = &info->scale_x;
4237       break;
4238
4239     case CLUTTER_Y_AXIS:
4240       pspec = obj_props[PROP_SCALE_Y];
4241       scale_p = &info->scale_y;
4242       break;
4243
4244     case CLUTTER_Z_AXIS:
4245       break;
4246     }
4247
4248   g_assert (pspec != NULL);
4249   g_assert (scale_p != NULL);
4250
4251   if (_clutter_actor_get_transition (self, pspec) == NULL)
4252     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4253   else
4254     _clutter_actor_update_transition (self, pspec, factor);
4255
4256   clutter_actor_queue_redraw (self);
4257 }
4258
4259 static inline void
4260 clutter_actor_set_scale_center (ClutterActor      *self,
4261                                 ClutterRotateAxis  axis,
4262                                 gfloat             coord)
4263 {
4264   GObject *obj = G_OBJECT (self);
4265   ClutterTransformInfo *info;
4266   gfloat center_x, center_y;
4267
4268   info = _clutter_actor_get_transform_info (self);
4269
4270   g_object_freeze_notify (obj);
4271
4272   /* get the current scale center coordinates */
4273   clutter_anchor_coord_get_units (self, &info->scale_center,
4274                                   &center_x,
4275                                   &center_y,
4276                                   NULL);
4277
4278   /* we need to notify this too, because setting explicit coordinates will
4279    * change the gravity as a side effect
4280    */
4281   if (info->scale_center.is_fractional)
4282     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4283
4284   switch (axis)
4285     {
4286     case CLUTTER_X_AXIS:
4287       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4288       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4289       break;
4290
4291     case CLUTTER_Y_AXIS:
4292       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4293       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4294       break;
4295
4296     default:
4297       g_assert_not_reached ();
4298     }
4299
4300   self->priv->transform_valid = FALSE;
4301
4302   clutter_actor_queue_redraw (self);
4303
4304   g_object_thaw_notify (obj);
4305 }
4306
4307 static inline void
4308 clutter_actor_set_scale_gravity (ClutterActor   *self,
4309                                  ClutterGravity  gravity)
4310 {
4311   ClutterTransformInfo *info;
4312   GObject *obj;
4313
4314   info = _clutter_actor_get_transform_info (self);
4315   obj = G_OBJECT (self);
4316
4317   if (gravity == CLUTTER_GRAVITY_NONE)
4318     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4319   else
4320     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4321
4322   self->priv->transform_valid = FALSE;
4323
4324   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4325   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4326   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4327
4328   clutter_actor_queue_redraw (self);
4329 }
4330
4331 static inline void
4332 clutter_actor_set_anchor_coord (ClutterActor      *self,
4333                                 ClutterRotateAxis  axis,
4334                                 gfloat             coord)
4335 {
4336   GObject *obj = G_OBJECT (self);
4337   ClutterTransformInfo *info;
4338   gfloat anchor_x, anchor_y;
4339
4340   info = _clutter_actor_get_transform_info (self);
4341
4342   g_object_freeze_notify (obj);
4343
4344   clutter_anchor_coord_get_units (self, &info->anchor,
4345                                   &anchor_x,
4346                                   &anchor_y,
4347                                   NULL);
4348
4349   if (info->anchor.is_fractional)
4350     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4351
4352   switch (axis)
4353     {
4354     case CLUTTER_X_AXIS:
4355       clutter_anchor_coord_set_units (&info->anchor,
4356                                       coord,
4357                                       anchor_y,
4358                                       0.0);
4359       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4360       break;
4361
4362     case CLUTTER_Y_AXIS:
4363       clutter_anchor_coord_set_units (&info->anchor,
4364                                       anchor_x,
4365                                       coord,
4366                                       0.0);
4367       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4368       break;
4369
4370     default:
4371       g_assert_not_reached ();
4372     }
4373
4374   self->priv->transform_valid = FALSE;
4375
4376   clutter_actor_queue_redraw (self);
4377
4378   g_object_thaw_notify (obj);
4379 }
4380
4381 static void
4382 clutter_actor_set_property (GObject      *object,
4383                             guint         prop_id,
4384                             const GValue *value,
4385                             GParamSpec   *pspec)
4386 {
4387   ClutterActor *actor = CLUTTER_ACTOR (object);
4388   ClutterActorPrivate *priv = actor->priv;
4389
4390   switch (prop_id)
4391     {
4392     case PROP_X:
4393       clutter_actor_set_x (actor, g_value_get_float (value));
4394       break;
4395
4396     case PROP_Y:
4397       clutter_actor_set_y (actor, g_value_get_float (value));
4398       break;
4399
4400     case PROP_POSITION:
4401       {
4402         const ClutterPoint *pos = g_value_get_boxed (value);
4403
4404         if (pos != NULL)
4405           clutter_actor_set_position (actor, pos->x, pos->y);
4406         else
4407           clutter_actor_set_fixed_position_set (actor, FALSE);
4408       }
4409       break;
4410
4411     case PROP_WIDTH:
4412       clutter_actor_set_width (actor, g_value_get_float (value));
4413       break;
4414
4415     case PROP_HEIGHT:
4416       clutter_actor_set_height (actor, g_value_get_float (value));
4417       break;
4418
4419     case PROP_SIZE:
4420       {
4421         const ClutterSize *size = g_value_get_boxed (value);
4422
4423         if (size != NULL)
4424           clutter_actor_set_size (actor, size->width, size->height);
4425         else
4426           clutter_actor_set_size (actor, -1, -1);
4427       }
4428       break;
4429
4430     case PROP_FIXED_X:
4431       clutter_actor_set_x (actor, g_value_get_float (value));
4432       break;
4433
4434     case PROP_FIXED_Y:
4435       clutter_actor_set_y (actor, g_value_get_float (value));
4436       break;
4437
4438     case PROP_FIXED_POSITION_SET:
4439       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4440       break;
4441
4442     case PROP_MIN_WIDTH:
4443       clutter_actor_set_min_width (actor, g_value_get_float (value));
4444       break;
4445
4446     case PROP_MIN_HEIGHT:
4447       clutter_actor_set_min_height (actor, g_value_get_float (value));
4448       break;
4449
4450     case PROP_NATURAL_WIDTH:
4451       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4452       break;
4453
4454     case PROP_NATURAL_HEIGHT:
4455       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4456       break;
4457
4458     case PROP_MIN_WIDTH_SET:
4459       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4460       break;
4461
4462     case PROP_MIN_HEIGHT_SET:
4463       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4464       break;
4465
4466     case PROP_NATURAL_WIDTH_SET:
4467       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4468       break;
4469
4470     case PROP_NATURAL_HEIGHT_SET:
4471       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4472       break;
4473
4474     case PROP_REQUEST_MODE:
4475       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4476       break;
4477
4478     case PROP_DEPTH:
4479       clutter_actor_set_depth (actor, g_value_get_float (value));
4480       break;
4481
4482     case PROP_OPACITY:
4483       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4484       break;
4485
4486     case PROP_OFFSCREEN_REDIRECT:
4487       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4488       break;
4489
4490     case PROP_NAME:
4491       clutter_actor_set_name (actor, g_value_get_string (value));
4492       break;
4493
4494     case PROP_VISIBLE:
4495       if (g_value_get_boolean (value) == TRUE)
4496         clutter_actor_show (actor);
4497       else
4498         clutter_actor_hide (actor);
4499       break;
4500
4501     case PROP_SCALE_X:
4502       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4503                                       g_value_get_double (value));
4504       break;
4505
4506     case PROP_SCALE_Y:
4507       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4508                                       g_value_get_double (value));
4509       break;
4510
4511     case PROP_SCALE_CENTER_X:
4512       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4513                                       g_value_get_float (value));
4514       break;
4515
4516     case PROP_SCALE_CENTER_Y:
4517       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4518                                       g_value_get_float (value));
4519       break;
4520
4521     case PROP_SCALE_GRAVITY:
4522       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4523       break;
4524
4525     case PROP_CLIP:
4526       {
4527         const ClutterGeometry *geom = g_value_get_boxed (value);
4528
4529         clutter_actor_set_clip (actor,
4530                                 geom->x, geom->y,
4531                                 geom->width, geom->height);
4532       }
4533       break;
4534
4535     case PROP_CLIP_TO_ALLOCATION:
4536       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4537       break;
4538
4539     case PROP_REACTIVE:
4540       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4541       break;
4542
4543     case PROP_ROTATION_ANGLE_X:
4544       clutter_actor_set_rotation_angle (actor,
4545                                         CLUTTER_X_AXIS,
4546                                         g_value_get_double (value));
4547       break;
4548
4549     case PROP_ROTATION_ANGLE_Y:
4550       clutter_actor_set_rotation_angle (actor,
4551                                         CLUTTER_Y_AXIS,
4552                                         g_value_get_double (value));
4553       break;
4554
4555     case PROP_ROTATION_ANGLE_Z:
4556       clutter_actor_set_rotation_angle (actor,
4557                                         CLUTTER_Z_AXIS,
4558                                         g_value_get_double (value));
4559       break;
4560
4561     case PROP_ROTATION_CENTER_X:
4562       clutter_actor_set_rotation_center_internal (actor,
4563                                                   CLUTTER_X_AXIS,
4564                                                   g_value_get_boxed (value));
4565       break;
4566
4567     case PROP_ROTATION_CENTER_Y:
4568       clutter_actor_set_rotation_center_internal (actor,
4569                                                   CLUTTER_Y_AXIS,
4570                                                   g_value_get_boxed (value));
4571       break;
4572
4573     case PROP_ROTATION_CENTER_Z:
4574       clutter_actor_set_rotation_center_internal (actor,
4575                                                   CLUTTER_Z_AXIS,
4576                                                   g_value_get_boxed (value));
4577       break;
4578
4579     case PROP_ROTATION_CENTER_Z_GRAVITY:
4580       {
4581         const ClutterTransformInfo *info;
4582
4583         info = _clutter_actor_get_transform_info_or_defaults (actor);
4584         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4585                                                    g_value_get_enum (value));
4586       }
4587       break;
4588
4589     case PROP_ANCHOR_X:
4590       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4591                                       g_value_get_float (value));
4592       break;
4593
4594     case PROP_ANCHOR_Y:
4595       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4596                                       g_value_get_float (value));
4597       break;
4598
4599     case PROP_ANCHOR_GRAVITY:
4600       clutter_actor_set_anchor_point_from_gravity (actor,
4601                                                    g_value_get_enum (value));
4602       break;
4603
4604     case PROP_SHOW_ON_SET_PARENT:
4605       priv->show_on_set_parent = g_value_get_boolean (value);
4606       break;
4607
4608     case PROP_TEXT_DIRECTION:
4609       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4610       break;
4611
4612     case PROP_ACTIONS:
4613       clutter_actor_add_action (actor, g_value_get_object (value));
4614       break;
4615
4616     case PROP_CONSTRAINTS:
4617       clutter_actor_add_constraint (actor, g_value_get_object (value));
4618       break;
4619
4620     case PROP_EFFECT:
4621       clutter_actor_add_effect (actor, g_value_get_object (value));
4622       break;
4623
4624     case PROP_LAYOUT_MANAGER:
4625       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4626       break;
4627
4628     case PROP_X_EXPAND:
4629       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4630       break;
4631
4632     case PROP_Y_EXPAND:
4633       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4634       break;
4635
4636     case PROP_X_ALIGN:
4637       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4638       break;
4639
4640     case PROP_Y_ALIGN:
4641       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4642       break;
4643
4644     case PROP_MARGIN_TOP:
4645       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4646       break;
4647
4648     case PROP_MARGIN_BOTTOM:
4649       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4650       break;
4651
4652     case PROP_MARGIN_LEFT:
4653       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4654       break;
4655
4656     case PROP_MARGIN_RIGHT:
4657       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4658       break;
4659
4660     case PROP_BACKGROUND_COLOR:
4661       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4662       break;
4663
4664     case PROP_CONTENT:
4665       clutter_actor_set_content (actor, g_value_get_object (value));
4666       break;
4667
4668     case PROP_CONTENT_GRAVITY:
4669       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4670       break;
4671
4672     case PROP_MINIFICATION_FILTER:
4673       clutter_actor_set_content_scaling_filters (actor,
4674                                                  g_value_get_enum (value),
4675                                                  actor->priv->mag_filter);
4676       break;
4677
4678     case PROP_MAGNIFICATION_FILTER:
4679       clutter_actor_set_content_scaling_filters (actor,
4680                                                  actor->priv->min_filter,
4681                                                  g_value_get_enum (value));
4682       break;
4683
4684     default:
4685       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4686       break;
4687     }
4688 }
4689
4690 static void
4691 clutter_actor_get_property (GObject    *object,
4692                             guint       prop_id,
4693                             GValue     *value,
4694                             GParamSpec *pspec)
4695 {
4696   ClutterActor *actor = CLUTTER_ACTOR (object);
4697   ClutterActorPrivate *priv = actor->priv;
4698
4699   switch (prop_id)
4700     {
4701     case PROP_X:
4702       g_value_set_float (value, clutter_actor_get_x (actor));
4703       break;
4704
4705     case PROP_Y:
4706       g_value_set_float (value, clutter_actor_get_y (actor));
4707       break;
4708
4709     case PROP_POSITION:
4710       {
4711         ClutterPoint position;
4712
4713         clutter_point_init (&position,
4714                             clutter_actor_get_x (actor),
4715                             clutter_actor_get_y (actor));
4716         g_value_set_boxed (value, &position);
4717       }
4718       break;
4719
4720     case PROP_WIDTH:
4721       g_value_set_float (value, clutter_actor_get_width (actor));
4722       break;
4723
4724     case PROP_HEIGHT:
4725       g_value_set_float (value, clutter_actor_get_height (actor));
4726       break;
4727
4728     case PROP_SIZE:
4729       {
4730         ClutterSize size;
4731
4732         clutter_size_init (&size,
4733                            clutter_actor_get_width (actor),
4734                            clutter_actor_get_height (actor));
4735         g_value_set_boxed (value, &size);
4736       }
4737       break;
4738
4739     case PROP_FIXED_X:
4740       {
4741         const ClutterLayoutInfo *info;
4742
4743         info = _clutter_actor_get_layout_info_or_defaults (actor);
4744         g_value_set_float (value, info->fixed_pos.x);
4745       }
4746       break;
4747
4748     case PROP_FIXED_Y:
4749       {
4750         const ClutterLayoutInfo *info;
4751
4752         info = _clutter_actor_get_layout_info_or_defaults (actor);
4753         g_value_set_float (value, info->fixed_pos.y);
4754       }
4755       break;
4756
4757     case PROP_FIXED_POSITION_SET:
4758       g_value_set_boolean (value, priv->position_set);
4759       break;
4760
4761     case PROP_MIN_WIDTH:
4762       {
4763         const ClutterLayoutInfo *info;
4764
4765         info = _clutter_actor_get_layout_info_or_defaults (actor);
4766         g_value_set_float (value, info->minimum.width);
4767       }
4768       break;
4769
4770     case PROP_MIN_HEIGHT:
4771       {
4772         const ClutterLayoutInfo *info;
4773
4774         info = _clutter_actor_get_layout_info_or_defaults (actor);
4775         g_value_set_float (value, info->minimum.height);
4776       }
4777       break;
4778
4779     case PROP_NATURAL_WIDTH:
4780       {
4781         const ClutterLayoutInfo *info;
4782
4783         info = _clutter_actor_get_layout_info_or_defaults (actor);
4784         g_value_set_float (value, info->natural.width);
4785       }
4786       break;
4787
4788     case PROP_NATURAL_HEIGHT:
4789       {
4790         const ClutterLayoutInfo *info;
4791
4792         info = _clutter_actor_get_layout_info_or_defaults (actor);
4793         g_value_set_float (value, info->natural.height);
4794       }
4795       break;
4796
4797     case PROP_MIN_WIDTH_SET:
4798       g_value_set_boolean (value, priv->min_width_set);
4799       break;
4800
4801     case PROP_MIN_HEIGHT_SET:
4802       g_value_set_boolean (value, priv->min_height_set);
4803       break;
4804
4805     case PROP_NATURAL_WIDTH_SET:
4806       g_value_set_boolean (value, priv->natural_width_set);
4807       break;
4808
4809     case PROP_NATURAL_HEIGHT_SET:
4810       g_value_set_boolean (value, priv->natural_height_set);
4811       break;
4812
4813     case PROP_REQUEST_MODE:
4814       g_value_set_enum (value, priv->request_mode);
4815       break;
4816
4817     case PROP_ALLOCATION:
4818       g_value_set_boxed (value, &priv->allocation);
4819       break;
4820
4821     case PROP_DEPTH:
4822       g_value_set_float (value, clutter_actor_get_depth (actor));
4823       break;
4824
4825     case PROP_OPACITY:
4826       g_value_set_uint (value, priv->opacity);
4827       break;
4828
4829     case PROP_OFFSCREEN_REDIRECT:
4830       g_value_set_enum (value, priv->offscreen_redirect);
4831       break;
4832
4833     case PROP_NAME:
4834       g_value_set_string (value, priv->name);
4835       break;
4836
4837     case PROP_VISIBLE:
4838       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4839       break;
4840
4841     case PROP_MAPPED:
4842       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4843       break;
4844
4845     case PROP_REALIZED:
4846       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4847       break;
4848
4849     case PROP_HAS_CLIP:
4850       g_value_set_boolean (value, priv->has_clip);
4851       break;
4852
4853     case PROP_CLIP:
4854       {
4855         ClutterGeometry clip;
4856
4857         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4858         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4859         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4860         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4861
4862         g_value_set_boxed (value, &clip);
4863       }
4864       break;
4865
4866     case PROP_CLIP_TO_ALLOCATION:
4867       g_value_set_boolean (value, priv->clip_to_allocation);
4868       break;
4869
4870     case PROP_SCALE_X:
4871       {
4872         const ClutterTransformInfo *info;
4873
4874         info = _clutter_actor_get_transform_info_or_defaults (actor);
4875         g_value_set_double (value, info->scale_x);
4876       }
4877       break;
4878
4879     case PROP_SCALE_Y:
4880       {
4881         const ClutterTransformInfo *info;
4882
4883         info = _clutter_actor_get_transform_info_or_defaults (actor);
4884         g_value_set_double (value, info->scale_y);
4885       }
4886       break;
4887
4888     case PROP_SCALE_CENTER_X:
4889       {
4890         gfloat center;
4891
4892         clutter_actor_get_scale_center (actor, &center, NULL);
4893
4894         g_value_set_float (value, center);
4895       }
4896       break;
4897
4898     case PROP_SCALE_CENTER_Y:
4899       {
4900         gfloat center;
4901
4902         clutter_actor_get_scale_center (actor, NULL, &center);
4903
4904         g_value_set_float (value, center);
4905       }
4906       break;
4907
4908     case PROP_SCALE_GRAVITY:
4909       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4910       break;
4911
4912     case PROP_REACTIVE:
4913       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4914       break;
4915
4916     case PROP_ROTATION_ANGLE_X:
4917       {
4918         const ClutterTransformInfo *info;
4919
4920         info = _clutter_actor_get_transform_info_or_defaults (actor);
4921         g_value_set_double (value, info->rx_angle);
4922       }
4923       break;
4924
4925     case PROP_ROTATION_ANGLE_Y:
4926       {
4927         const ClutterTransformInfo *info;
4928
4929         info = _clutter_actor_get_transform_info_or_defaults (actor);
4930         g_value_set_double (value, info->ry_angle);
4931       }
4932       break;
4933
4934     case PROP_ROTATION_ANGLE_Z:
4935       {
4936         const ClutterTransformInfo *info;
4937
4938         info = _clutter_actor_get_transform_info_or_defaults (actor);
4939         g_value_set_double (value, info->rz_angle);
4940       }
4941       break;
4942
4943     case PROP_ROTATION_CENTER_X:
4944       {
4945         ClutterVertex center;
4946
4947         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4948                                     &center.x,
4949                                     &center.y,
4950                                     &center.z);
4951
4952         g_value_set_boxed (value, &center);
4953       }
4954       break;
4955
4956     case PROP_ROTATION_CENTER_Y:
4957       {
4958         ClutterVertex center;
4959
4960         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4961                                     &center.x,
4962                                     &center.y,
4963                                     &center.z);
4964
4965         g_value_set_boxed (value, &center);
4966       }
4967       break;
4968
4969     case PROP_ROTATION_CENTER_Z:
4970       {
4971         ClutterVertex center;
4972
4973         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4974                                     &center.x,
4975                                     &center.y,
4976                                     &center.z);
4977
4978         g_value_set_boxed (value, &center);
4979       }
4980       break;
4981
4982     case PROP_ROTATION_CENTER_Z_GRAVITY:
4983       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4984       break;
4985
4986     case PROP_ANCHOR_X:
4987       {
4988         const ClutterTransformInfo *info;
4989         gfloat anchor_x;
4990
4991         info = _clutter_actor_get_transform_info_or_defaults (actor);
4992         clutter_anchor_coord_get_units (actor, &info->anchor,
4993                                         &anchor_x,
4994                                         NULL,
4995                                         NULL);
4996         g_value_set_float (value, anchor_x);
4997       }
4998       break;
4999
5000     case PROP_ANCHOR_Y:
5001       {
5002         const ClutterTransformInfo *info;
5003         gfloat anchor_y;
5004
5005         info = _clutter_actor_get_transform_info_or_defaults (actor);
5006         clutter_anchor_coord_get_units (actor, &info->anchor,
5007                                         NULL,
5008                                         &anchor_y,
5009                                         NULL);
5010         g_value_set_float (value, anchor_y);
5011       }
5012       break;
5013
5014     case PROP_ANCHOR_GRAVITY:
5015       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5016       break;
5017
5018     case PROP_SHOW_ON_SET_PARENT:
5019       g_value_set_boolean (value, priv->show_on_set_parent);
5020       break;
5021
5022     case PROP_TEXT_DIRECTION:
5023       g_value_set_enum (value, priv->text_direction);
5024       break;
5025
5026     case PROP_HAS_POINTER:
5027       g_value_set_boolean (value, priv->has_pointer);
5028       break;
5029
5030     case PROP_LAYOUT_MANAGER:
5031       g_value_set_object (value, priv->layout_manager);
5032       break;
5033
5034     case PROP_X_EXPAND:
5035       {
5036         const ClutterLayoutInfo *info;
5037
5038         info = _clutter_actor_get_layout_info_or_defaults (actor);
5039         g_value_set_boolean (value, info->x_expand);
5040       }
5041       break;
5042
5043     case PROP_Y_EXPAND:
5044       {
5045         const ClutterLayoutInfo *info;
5046
5047         info = _clutter_actor_get_layout_info_or_defaults (actor);
5048         g_value_set_boolean (value, info->y_expand);
5049       }
5050       break;
5051
5052     case PROP_X_ALIGN:
5053       {
5054         const ClutterLayoutInfo *info;
5055
5056         info = _clutter_actor_get_layout_info_or_defaults (actor);
5057         g_value_set_enum (value, info->x_align);
5058       }
5059       break;
5060
5061     case PROP_Y_ALIGN:
5062       {
5063         const ClutterLayoutInfo *info;
5064
5065         info = _clutter_actor_get_layout_info_or_defaults (actor);
5066         g_value_set_enum (value, info->y_align);
5067       }
5068       break;
5069
5070     case PROP_MARGIN_TOP:
5071       {
5072         const ClutterLayoutInfo *info;
5073
5074         info = _clutter_actor_get_layout_info_or_defaults (actor);
5075         g_value_set_float (value, info->margin.top);
5076       }
5077       break;
5078
5079     case PROP_MARGIN_BOTTOM:
5080       {
5081         const ClutterLayoutInfo *info;
5082
5083         info = _clutter_actor_get_layout_info_or_defaults (actor);
5084         g_value_set_float (value, info->margin.bottom);
5085       }
5086       break;
5087
5088     case PROP_MARGIN_LEFT:
5089       {
5090         const ClutterLayoutInfo *info;
5091
5092         info = _clutter_actor_get_layout_info_or_defaults (actor);
5093         g_value_set_float (value, info->margin.left);
5094       }
5095       break;
5096
5097     case PROP_MARGIN_RIGHT:
5098       {
5099         const ClutterLayoutInfo *info;
5100
5101         info = _clutter_actor_get_layout_info_or_defaults (actor);
5102         g_value_set_float (value, info->margin.right);
5103       }
5104       break;
5105
5106     case PROP_BACKGROUND_COLOR_SET:
5107       g_value_set_boolean (value, priv->bg_color_set);
5108       break;
5109
5110     case PROP_BACKGROUND_COLOR:
5111       g_value_set_boxed (value, &priv->bg_color);
5112       break;
5113
5114     case PROP_FIRST_CHILD:
5115       g_value_set_object (value, priv->first_child);
5116       break;
5117
5118     case PROP_LAST_CHILD:
5119       g_value_set_object (value, priv->last_child);
5120       break;
5121
5122     case PROP_CONTENT:
5123       g_value_set_object (value, priv->content);
5124       break;
5125
5126     case PROP_CONTENT_GRAVITY:
5127       g_value_set_enum (value, priv->content_gravity);
5128       break;
5129
5130     case PROP_CONTENT_BOX:
5131       {
5132         ClutterActorBox box = { 0, };
5133
5134         clutter_actor_get_content_box (actor, &box);
5135         g_value_set_boxed (value, &box);
5136       }
5137       break;
5138
5139     case PROP_MINIFICATION_FILTER:
5140       g_value_set_enum (value, priv->min_filter);
5141       break;
5142
5143     case PROP_MAGNIFICATION_FILTER:
5144       g_value_set_enum (value, priv->mag_filter);
5145       break;
5146
5147     default:
5148       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5149       break;
5150     }
5151 }
5152
5153 static void
5154 clutter_actor_dispose (GObject *object)
5155 {
5156   ClutterActor *self = CLUTTER_ACTOR (object);
5157   ClutterActorPrivate *priv = self->priv;
5158
5159   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5160                 priv->id,
5161                 g_type_name (G_OBJECT_TYPE (self)),
5162                 object->ref_count);
5163
5164   g_signal_emit (self, actor_signals[DESTROY], 0);
5165
5166   /* avoid recursing when called from clutter_actor_destroy() */
5167   if (priv->parent != NULL)
5168     {
5169       ClutterActor *parent = priv->parent;
5170
5171       /* go through the Container implementation unless this
5172        * is an internal child and has been marked as such.
5173        *
5174        * removing the actor from its parent will reset the
5175        * realized and mapped states.
5176        */
5177       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5178         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5179       else
5180         clutter_actor_remove_child_internal (parent, self,
5181                                              REMOVE_CHILD_LEGACY_FLAGS);
5182     }
5183
5184   /* parent must be gone at this point */
5185   g_assert (priv->parent == NULL);
5186
5187   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5188     {
5189       /* can't be mapped or realized with no parent */
5190       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5191       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5192     }
5193
5194   g_clear_object (&priv->pango_context);
5195   g_clear_object (&priv->actions);
5196   g_clear_object (&priv->constraints);
5197   g_clear_object (&priv->effects);
5198   g_clear_object (&priv->flatten_effect);
5199
5200   if (priv->layout_manager != NULL)
5201     {
5202       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5203       g_clear_object (&priv->layout_manager);
5204     }
5205
5206   if (priv->content != NULL)
5207     {
5208       _clutter_content_detached (priv->content, self);
5209       g_clear_object (&priv->content);
5210     }
5211
5212   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5213 }
5214
5215 static void
5216 clutter_actor_finalize (GObject *object)
5217 {
5218   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5219
5220   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5221                 priv->name != NULL ? priv->name : "<none>",
5222                 priv->id,
5223                 g_type_name (G_OBJECT_TYPE (object)));
5224
5225   _clutter_context_release_id (priv->id);
5226
5227   g_free (priv->name);
5228
5229   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5230 }
5231
5232
5233 /**
5234  * clutter_actor_get_accessible:
5235  * @self: a #ClutterActor
5236  *
5237  * Returns the accessible object that describes the actor to an
5238  * assistive technology.
5239  *
5240  * If no class-specific #AtkObject implementation is available for the
5241  * actor instance in question, it will inherit an #AtkObject
5242  * implementation from the first ancestor class for which such an
5243  * implementation is defined.
5244  *
5245  * The documentation of the <ulink
5246  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5247  * library contains more information about accessible objects and
5248  * their uses.
5249  *
5250  * Returns: (transfer none): the #AtkObject associated with @actor
5251  */
5252 AtkObject *
5253 clutter_actor_get_accessible (ClutterActor *self)
5254 {
5255   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5256
5257   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5258 }
5259
5260 static AtkObject *
5261 clutter_actor_real_get_accessible (ClutterActor *actor)
5262 {
5263   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5264 }
5265
5266 static AtkObject *
5267 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5268 {
5269   AtkObject *accessible;
5270
5271   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5272   if (accessible != NULL)
5273     g_object_ref (accessible);
5274
5275   return accessible;
5276 }
5277
5278 static void
5279 atk_implementor_iface_init (AtkImplementorIface *iface)
5280 {
5281   iface->ref_accessible = _clutter_actor_ref_accessible;
5282 }
5283
5284 static gboolean
5285 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5286                                            ClutterPaintVolume *volume)
5287 {
5288   ClutterActorPrivate *priv = self->priv;
5289   gboolean res = TRUE;
5290
5291   /* we start from the allocation */
5292   clutter_paint_volume_set_width (volume,
5293                                   priv->allocation.x2 - priv->allocation.x1);
5294   clutter_paint_volume_set_height (volume,
5295                                    priv->allocation.y2 - priv->allocation.y1);
5296
5297   /* if the actor has a clip set then we have a pretty definite
5298    * size for the paint volume: the actor cannot possibly paint
5299    * outside the clip region.
5300    */
5301   if (priv->clip_to_allocation)
5302     {
5303       /* the allocation has already been set, so we just flip the
5304        * return value
5305        */
5306       res = TRUE;
5307     }
5308   else
5309     {
5310       ClutterActor *child;
5311
5312       if (priv->has_clip &&
5313           priv->clip.width >= 0 &&
5314           priv->clip.height >= 0)
5315         {
5316           ClutterVertex origin;
5317
5318           origin.x = priv->clip.x;
5319           origin.y = priv->clip.y;
5320           origin.z = 0;
5321
5322           clutter_paint_volume_set_origin (volume, &origin);
5323           clutter_paint_volume_set_width (volume, priv->clip.width);
5324           clutter_paint_volume_set_height (volume, priv->clip.height);
5325
5326           res = TRUE;
5327         }
5328
5329       /* if we don't have children we just bail out here... */
5330       if (priv->n_children == 0)
5331         return res;
5332
5333       /* ...but if we have children then we ask for their paint volume in
5334        * our coordinates. if any of our children replies that it doesn't
5335        * have a paint volume, we bail out
5336        */
5337       for (child = priv->first_child;
5338            child != NULL;
5339            child = child->priv->next_sibling)
5340         {
5341           const ClutterPaintVolume *child_volume;
5342
5343           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5344             continue;
5345
5346           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5347           if (child_volume == NULL)
5348             {
5349               res = FALSE;
5350               break;
5351             }
5352
5353           clutter_paint_volume_union (volume, child_volume);
5354           res = TRUE;
5355         }
5356     }
5357
5358   return res;
5359
5360 }
5361
5362 static gboolean
5363 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5364                                      ClutterPaintVolume *volume)
5365 {
5366   ClutterActorClass *klass;
5367   gboolean res;
5368
5369   klass = CLUTTER_ACTOR_GET_CLASS (self);
5370
5371   /* XXX - this thoroughly sucks, but we don't want to penalize users
5372    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5373    * redraw. This should go away in 2.0.
5374    */
5375   if (klass->paint == clutter_actor_real_paint &&
5376       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5377     {
5378       res = TRUE;
5379     }
5380   else
5381     {
5382       /* this is the default return value: we cannot know if a class
5383        * is going to paint outside its allocation, so we take the
5384        * conservative approach.
5385        */
5386       res = FALSE;
5387     }
5388
5389   /* update_default_paint_volume() should only fail if one of the children
5390    * reported an invalid, or no, paint volume
5391    */
5392   if (!clutter_actor_update_default_paint_volume (self, volume))
5393     return FALSE;
5394
5395   return res;
5396 }
5397
5398 /**
5399  * clutter_actor_get_default_paint_volume:
5400  * @self: a #ClutterActor
5401  *
5402  * Retrieves the default paint volume for @self.
5403  *
5404  * This function provides the same #ClutterPaintVolume that would be
5405  * computed by the default implementation inside #ClutterActor of the
5406  * #ClutterActorClass.get_paint_volume() virtual function.
5407  *
5408  * This function should only be used by #ClutterActor subclasses that
5409  * cannot chain up to the parent implementation when computing their
5410  * paint volume.
5411  *
5412  * Return value: (transfer none): a pointer to the default
5413  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5414  *   the actor could not compute a valid paint volume. The returned value
5415  *   is not guaranteed to be stable across multiple frames, so if you
5416  *   want to retain it, you will need to copy it using
5417  *   clutter_paint_volume_copy().
5418  *
5419  * Since: 1.10
5420  */
5421 const ClutterPaintVolume *
5422 clutter_actor_get_default_paint_volume (ClutterActor *self)
5423 {
5424   ClutterPaintVolume volume;
5425   ClutterPaintVolume *res;
5426
5427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5428
5429   res = NULL;
5430   _clutter_paint_volume_init_static (&volume, self);
5431   if (clutter_actor_update_default_paint_volume (self, &volume))
5432     {
5433       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5434
5435       if (stage != NULL)
5436         {
5437           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5438           _clutter_paint_volume_copy_static (&volume, res);
5439         }
5440     }
5441
5442   clutter_paint_volume_free (&volume);
5443
5444   return res;
5445 }
5446
5447 static gboolean
5448 clutter_actor_real_has_overlaps (ClutterActor *self)
5449 {
5450   /* By default we'll assume that all actors need an offscreen redirect to get
5451    * the correct opacity. Actors such as ClutterTexture that would never need
5452    * an offscreen redirect can override this to return FALSE. */
5453   return TRUE;
5454 }
5455
5456 static void
5457 clutter_actor_real_destroy (ClutterActor *actor)
5458 {
5459   ClutterActorIter iter;
5460
5461   g_object_freeze_notify (G_OBJECT (actor));
5462
5463   clutter_actor_iter_init (&iter, actor);
5464   while (clutter_actor_iter_next (&iter, NULL))
5465     clutter_actor_iter_destroy (&iter);
5466
5467   g_object_thaw_notify (G_OBJECT (actor));
5468 }
5469
5470 static GObject *
5471 clutter_actor_constructor (GType gtype,
5472                            guint n_props,
5473                            GObjectConstructParam *props)
5474 {
5475   GObjectClass *gobject_class;
5476   ClutterActor *self;
5477   GObject *retval;
5478
5479   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5480   retval = gobject_class->constructor (gtype, n_props, props);
5481   self = CLUTTER_ACTOR (retval);
5482
5483   if (self->priv->layout_manager == NULL)
5484     {
5485       ClutterLayoutManager *default_layout;
5486
5487       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5488
5489       default_layout = clutter_fixed_layout_new ();
5490       clutter_actor_set_layout_manager (self, default_layout);
5491     }
5492
5493   return retval;
5494 }
5495
5496 static void
5497 clutter_actor_class_init (ClutterActorClass *klass)
5498 {
5499   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5500
5501   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5502   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5503   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5504   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5505
5506   object_class->constructor = clutter_actor_constructor;
5507   object_class->set_property = clutter_actor_set_property;
5508   object_class->get_property = clutter_actor_get_property;
5509   object_class->dispose = clutter_actor_dispose;
5510   object_class->finalize = clutter_actor_finalize;
5511
5512   klass->show = clutter_actor_real_show;
5513   klass->show_all = clutter_actor_show;
5514   klass->hide = clutter_actor_real_hide;
5515   klass->hide_all = clutter_actor_hide;
5516   klass->map = clutter_actor_real_map;
5517   klass->unmap = clutter_actor_real_unmap;
5518   klass->unrealize = clutter_actor_real_unrealize;
5519   klass->pick = clutter_actor_real_pick;
5520   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5521   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5522   klass->allocate = clutter_actor_real_allocate;
5523   klass->queue_redraw = clutter_actor_real_queue_redraw;
5524   klass->queue_relayout = clutter_actor_real_queue_relayout;
5525   klass->apply_transform = clutter_actor_real_apply_transform;
5526   klass->get_accessible = clutter_actor_real_get_accessible;
5527   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5528   klass->has_overlaps = clutter_actor_real_has_overlaps;
5529   klass->paint = clutter_actor_real_paint;
5530   klass->destroy = clutter_actor_real_destroy;
5531
5532   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5533
5534   /**
5535    * ClutterActor:x:
5536    *
5537    * X coordinate of the actor in pixels. If written, forces a fixed
5538    * position for the actor. If read, returns the fixed position if any,
5539    * otherwise the allocation if available, otherwise 0.
5540    *
5541    * The #ClutterActor:x property is animatable.
5542    */
5543   obj_props[PROP_X] =
5544     g_param_spec_float ("x",
5545                         P_("X coordinate"),
5546                         P_("X coordinate of the actor"),
5547                         -G_MAXFLOAT, G_MAXFLOAT,
5548                         0.0,
5549                         G_PARAM_READWRITE |
5550                         G_PARAM_STATIC_STRINGS |
5551                         CLUTTER_PARAM_ANIMATABLE);
5552
5553   /**
5554    * ClutterActor:y:
5555    *
5556    * Y coordinate of the actor in pixels. If written, forces a fixed
5557    * position for the actor.  If read, returns the fixed position if
5558    * any, otherwise the allocation if available, otherwise 0.
5559    *
5560    * The #ClutterActor:y property is animatable.
5561    */
5562   obj_props[PROP_Y] =
5563     g_param_spec_float ("y",
5564                         P_("Y coordinate"),
5565                         P_("Y coordinate of the actor"),
5566                         -G_MAXFLOAT, G_MAXFLOAT,
5567                         0.0,
5568                         G_PARAM_READWRITE |
5569                         G_PARAM_STATIC_STRINGS |
5570                         CLUTTER_PARAM_ANIMATABLE);
5571
5572   /**
5573    * ClutterActor:position:
5574    *
5575    * The position of the origin of the actor.
5576    *
5577    * This property is a shorthand for setting and getting the
5578    * #ClutterActor:x and #ClutterActor:y properties at the same
5579    * time.
5580    *
5581    * The #ClutterActor:position property is animatable.
5582    *
5583    * Since: 1.12
5584    */
5585   obj_props[PROP_POSITION] =
5586     g_param_spec_boxed ("position",
5587                         P_("Position"),
5588                         P_("The position of the origin of the actor"),
5589                         CLUTTER_TYPE_POINT,
5590                         G_PARAM_READWRITE |
5591                         G_PARAM_STATIC_STRINGS |
5592                         CLUTTER_PARAM_ANIMATABLE);
5593
5594   /**
5595    * ClutterActor:width:
5596    *
5597    * Width of the actor (in pixels). If written, forces the minimum and
5598    * natural size request of the actor to the given width. If read, returns
5599    * the allocated width if available, otherwise the width request.
5600    *
5601    * The #ClutterActor:width property is animatable.
5602    */
5603   obj_props[PROP_WIDTH] =
5604     g_param_spec_float ("width",
5605                         P_("Width"),
5606                         P_("Width of the actor"),
5607                         0.0, G_MAXFLOAT,
5608                         0.0,
5609                         G_PARAM_READWRITE |
5610                         G_PARAM_STATIC_STRINGS |
5611                         CLUTTER_PARAM_ANIMATABLE);
5612
5613   /**
5614    * ClutterActor:height:
5615    *
5616    * Height of the actor (in pixels).  If written, forces the minimum and
5617    * natural size request of the actor to the given height. If read, returns
5618    * the allocated height if available, otherwise the height request.
5619    *
5620    * The #ClutterActor:height property is animatable.
5621    */
5622   obj_props[PROP_HEIGHT] =
5623     g_param_spec_float ("height",
5624                         P_("Height"),
5625                         P_("Height of the actor"),
5626                         0.0, G_MAXFLOAT,
5627                         0.0,
5628                         G_PARAM_READWRITE |
5629                         G_PARAM_STATIC_STRINGS |
5630                         CLUTTER_PARAM_ANIMATABLE);
5631
5632   /**
5633    * ClutterActor:size:
5634    *
5635    * The size of the actor.
5636    *
5637    * This property is a shorthand for setting and getting the
5638    * #ClutterActor:width and #ClutterActor:height at the same time.
5639    *
5640    * The #ClutterActor:size property is animatable.
5641    *
5642    * Since: 1.12
5643    */
5644   obj_props[PROP_SIZE] =
5645     g_param_spec_boxed ("size",
5646                         P_("Size"),
5647                         P_("The size of the actor"),
5648                         CLUTTER_TYPE_SIZE,
5649                         G_PARAM_READWRITE |
5650                         G_PARAM_STATIC_STRINGS |
5651                         CLUTTER_PARAM_ANIMATABLE);
5652
5653   /**
5654    * ClutterActor:fixed-x:
5655    *
5656    * The fixed X position of the actor in pixels.
5657    *
5658    * Writing this property sets #ClutterActor:fixed-position-set
5659    * property as well, as a side effect
5660    *
5661    * Since: 0.8
5662    */
5663   obj_props[PROP_FIXED_X] =
5664     g_param_spec_float ("fixed-x",
5665                         P_("Fixed X"),
5666                         P_("Forced X position of the actor"),
5667                         -G_MAXFLOAT, G_MAXFLOAT,
5668                         0.0,
5669                         CLUTTER_PARAM_READWRITE);
5670
5671   /**
5672    * ClutterActor:fixed-y:
5673    *
5674    * The fixed Y position of the actor in pixels.
5675    *
5676    * Writing this property sets the #ClutterActor:fixed-position-set
5677    * property as well, as a side effect
5678    *
5679    * Since: 0.8
5680    */
5681   obj_props[PROP_FIXED_Y] =
5682     g_param_spec_float ("fixed-y",
5683                         P_("Fixed Y"),
5684                         P_("Forced Y position of the actor"),
5685                         -G_MAXFLOAT, G_MAXFLOAT,
5686                         0,
5687                         CLUTTER_PARAM_READWRITE);
5688
5689   /**
5690    * ClutterActor:fixed-position-set:
5691    *
5692    * This flag controls whether the #ClutterActor:fixed-x and
5693    * #ClutterActor:fixed-y properties are used
5694    *
5695    * Since: 0.8
5696    */
5697   obj_props[PROP_FIXED_POSITION_SET] =
5698     g_param_spec_boolean ("fixed-position-set",
5699                           P_("Fixed position set"),
5700                           P_("Whether to use fixed positioning for the actor"),
5701                           FALSE,
5702                           CLUTTER_PARAM_READWRITE);
5703
5704   /**
5705    * ClutterActor:min-width:
5706    *
5707    * A forced minimum width request for the actor, in pixels
5708    *
5709    * Writing this property sets the #ClutterActor:min-width-set property
5710    * as well, as a side effect.
5711    *
5712    *This property overrides the usual width request of the actor.
5713    *
5714    * Since: 0.8
5715    */
5716   obj_props[PROP_MIN_WIDTH] =
5717     g_param_spec_float ("min-width",
5718                         P_("Min Width"),
5719                         P_("Forced minimum width request for the actor"),
5720                         0.0, G_MAXFLOAT,
5721                         0.0,
5722                         CLUTTER_PARAM_READWRITE);
5723
5724   /**
5725    * ClutterActor:min-height:
5726    *
5727    * A forced minimum height request for the actor, in pixels
5728    *
5729    * Writing this property sets the #ClutterActor:min-height-set property
5730    * as well, as a side effect. This property overrides the usual height
5731    * request of the actor.
5732    *
5733    * Since: 0.8
5734    */
5735   obj_props[PROP_MIN_HEIGHT] =
5736     g_param_spec_float ("min-height",
5737                         P_("Min Height"),
5738                         P_("Forced minimum height request for the actor"),
5739                         0.0, G_MAXFLOAT,
5740                         0.0,
5741                         CLUTTER_PARAM_READWRITE);
5742
5743   /**
5744    * ClutterActor:natural-width:
5745    *
5746    * A forced natural width request for the actor, in pixels
5747    *
5748    * Writing this property sets the #ClutterActor:natural-width-set
5749    * property as well, as a side effect. This property overrides the
5750    * usual width request of the actor
5751    *
5752    * Since: 0.8
5753    */
5754   obj_props[PROP_NATURAL_WIDTH] =
5755     g_param_spec_float ("natural-width",
5756                         P_("Natural Width"),
5757                         P_("Forced natural width request for the actor"),
5758                         0.0, G_MAXFLOAT,
5759                         0.0,
5760                         CLUTTER_PARAM_READWRITE);
5761
5762   /**
5763    * ClutterActor:natural-height:
5764    *
5765    * A forced natural height request for the actor, in pixels
5766    *
5767    * Writing this property sets the #ClutterActor:natural-height-set
5768    * property as well, as a side effect. This property overrides the
5769    * usual height request of the actor
5770    *
5771    * Since: 0.8
5772    */
5773   obj_props[PROP_NATURAL_HEIGHT] =
5774     g_param_spec_float ("natural-height",
5775                         P_("Natural Height"),
5776                         P_("Forced natural height request for the actor"),
5777                         0.0, G_MAXFLOAT,
5778                         0.0,
5779                         CLUTTER_PARAM_READWRITE);
5780
5781   /**
5782    * ClutterActor:min-width-set:
5783    *
5784    * This flag controls whether the #ClutterActor:min-width property
5785    * is used
5786    *
5787    * Since: 0.8
5788    */
5789   obj_props[PROP_MIN_WIDTH_SET] =
5790     g_param_spec_boolean ("min-width-set",
5791                           P_("Minimum width set"),
5792                           P_("Whether to use the min-width property"),
5793                           FALSE,
5794                           CLUTTER_PARAM_READWRITE);
5795
5796   /**
5797    * ClutterActor:min-height-set:
5798    *
5799    * This flag controls whether the #ClutterActor:min-height property
5800    * is used
5801    *
5802    * Since: 0.8
5803    */
5804   obj_props[PROP_MIN_HEIGHT_SET] =
5805     g_param_spec_boolean ("min-height-set",
5806                           P_("Minimum height set"),
5807                           P_("Whether to use the min-height property"),
5808                           FALSE,
5809                           CLUTTER_PARAM_READWRITE);
5810
5811   /**
5812    * ClutterActor:natural-width-set:
5813    *
5814    * This flag controls whether the #ClutterActor:natural-width property
5815    * is used
5816    *
5817    * Since: 0.8
5818    */
5819   obj_props[PROP_NATURAL_WIDTH_SET] =
5820     g_param_spec_boolean ("natural-width-set",
5821                           P_("Natural width set"),
5822                           P_("Whether to use the natural-width property"),
5823                           FALSE,
5824                           CLUTTER_PARAM_READWRITE);
5825
5826   /**
5827    * ClutterActor:natural-height-set:
5828    *
5829    * This flag controls whether the #ClutterActor:natural-height property
5830    * is used
5831    *
5832    * Since: 0.8
5833    */
5834   obj_props[PROP_NATURAL_HEIGHT_SET] =
5835     g_param_spec_boolean ("natural-height-set",
5836                           P_("Natural height set"),
5837                           P_("Whether to use the natural-height property"),
5838                           FALSE,
5839                           CLUTTER_PARAM_READWRITE);
5840
5841   /**
5842    * ClutterActor:allocation:
5843    *
5844    * The allocation for the actor, in pixels
5845    *
5846    * This is property is read-only, but you might monitor it to know when an
5847    * actor moves or resizes
5848    *
5849    * Since: 0.8
5850    */
5851   obj_props[PROP_ALLOCATION] =
5852     g_param_spec_boxed ("allocation",
5853                         P_("Allocation"),
5854                         P_("The actor's allocation"),
5855                         CLUTTER_TYPE_ACTOR_BOX,
5856                         CLUTTER_PARAM_READABLE);
5857
5858   /**
5859    * ClutterActor:request-mode:
5860    *
5861    * Request mode for the #ClutterActor. The request mode determines the
5862    * type of geometry management used by the actor, either height for width
5863    * (the default) or width for height.
5864    *
5865    * For actors implementing height for width, the parent container should get
5866    * the preferred width first, and then the preferred height for that width.
5867    *
5868    * For actors implementing width for height, the parent container should get
5869    * the preferred height first, and then the preferred width for that height.
5870    *
5871    * For instance:
5872    *
5873    * |[
5874    *   ClutterRequestMode mode;
5875    *   gfloat natural_width, min_width;
5876    *   gfloat natural_height, min_height;
5877    *
5878    *   mode = clutter_actor_get_request_mode (child);
5879    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5880    *     {
5881    *       clutter_actor_get_preferred_width (child, -1,
5882    *                                          &amp;min_width,
5883    *                                          &amp;natural_width);
5884    *       clutter_actor_get_preferred_height (child, natural_width,
5885    *                                           &amp;min_height,
5886    *                                           &amp;natural_height);
5887    *     }
5888    *   else
5889    *     {
5890    *       clutter_actor_get_preferred_height (child, -1,
5891    *                                           &amp;min_height,
5892    *                                           &amp;natural_height);
5893    *       clutter_actor_get_preferred_width (child, natural_height,
5894    *                                          &amp;min_width,
5895    *                                          &amp;natural_width);
5896    *     }
5897    * ]|
5898    *
5899    * will retrieve the minimum and natural width and height depending on the
5900    * preferred request mode of the #ClutterActor "child".
5901    *
5902    * The clutter_actor_get_preferred_size() function will implement this
5903    * check for you.
5904    *
5905    * Since: 0.8
5906    */
5907   obj_props[PROP_REQUEST_MODE] =
5908     g_param_spec_enum ("request-mode",
5909                        P_("Request Mode"),
5910                        P_("The actor's request mode"),
5911                        CLUTTER_TYPE_REQUEST_MODE,
5912                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5913                        CLUTTER_PARAM_READWRITE);
5914
5915   /**
5916    * ClutterActor:depth:
5917    *
5918    * The position of the actor on the Z axis.
5919    *
5920    * The #ClutterActor:depth property is relative to the parent's
5921    * modelview matrix.
5922    *
5923    * The #ClutterActor:depth property is animatable.
5924    *
5925    * Since: 0.6
5926    */
5927   obj_props[PROP_DEPTH] =
5928     g_param_spec_float ("depth",
5929                         P_("Depth"),
5930                         P_("Position on the Z axis"),
5931                         -G_MAXFLOAT, G_MAXFLOAT,
5932                         0.0,
5933                         G_PARAM_READWRITE |
5934                         G_PARAM_STATIC_STRINGS |
5935                         CLUTTER_PARAM_ANIMATABLE);
5936
5937   /**
5938    * ClutterActor:opacity:
5939    *
5940    * Opacity of an actor, between 0 (fully transparent) and
5941    * 255 (fully opaque)
5942    *
5943    * The #ClutterActor:opacity property is animatable.
5944    */
5945   obj_props[PROP_OPACITY] =
5946     g_param_spec_uint ("opacity",
5947                        P_("Opacity"),
5948                        P_("Opacity of an actor"),
5949                        0, 255,
5950                        255,
5951                        G_PARAM_READWRITE |
5952                        G_PARAM_STATIC_STRINGS |
5953                        CLUTTER_PARAM_ANIMATABLE);
5954
5955   /**
5956    * ClutterActor:offscreen-redirect:
5957    *
5958    * Determines the conditions in which the actor will be redirected
5959    * to an offscreen framebuffer while being painted. For example this
5960    * can be used to cache an actor in a framebuffer or for improved
5961    * handling of transparent actors. See
5962    * clutter_actor_set_offscreen_redirect() for details.
5963    *
5964    * Since: 1.8
5965    */
5966   obj_props[PROP_OFFSCREEN_REDIRECT] =
5967     g_param_spec_flags ("offscreen-redirect",
5968                         P_("Offscreen redirect"),
5969                         P_("Flags controlling when to flatten the actor into a single image"),
5970                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5971                         0,
5972                         CLUTTER_PARAM_READWRITE);
5973
5974   /**
5975    * ClutterActor:visible:
5976    *
5977    * Whether the actor is set to be visible or not
5978    *
5979    * See also #ClutterActor:mapped
5980    */
5981   obj_props[PROP_VISIBLE] =
5982     g_param_spec_boolean ("visible",
5983                           P_("Visible"),
5984                           P_("Whether the actor is visible or not"),
5985                           FALSE,
5986                           CLUTTER_PARAM_READWRITE);
5987
5988   /**
5989    * ClutterActor:mapped:
5990    *
5991    * Whether the actor is mapped (will be painted when the stage
5992    * to which it belongs is mapped)
5993    *
5994    * Since: 1.0
5995    */
5996   obj_props[PROP_MAPPED] =
5997     g_param_spec_boolean ("mapped",
5998                           P_("Mapped"),
5999                           P_("Whether the actor will be painted"),
6000                           FALSE,
6001                           CLUTTER_PARAM_READABLE);
6002
6003   /**
6004    * ClutterActor:realized:
6005    *
6006    * Whether the actor has been realized
6007    *
6008    * Since: 1.0
6009    */
6010   obj_props[PROP_REALIZED] =
6011     g_param_spec_boolean ("realized",
6012                           P_("Realized"),
6013                           P_("Whether the actor has been realized"),
6014                           FALSE,
6015                           CLUTTER_PARAM_READABLE);
6016
6017   /**
6018    * ClutterActor:reactive:
6019    *
6020    * Whether the actor is reactive to events or not
6021    *
6022    * Only reactive actors will emit event-related signals
6023    *
6024    * Since: 0.6
6025    */
6026   obj_props[PROP_REACTIVE] =
6027     g_param_spec_boolean ("reactive",
6028                           P_("Reactive"),
6029                           P_("Whether the actor is reactive to events"),
6030                           FALSE,
6031                           CLUTTER_PARAM_READWRITE);
6032
6033   /**
6034    * ClutterActor:has-clip:
6035    *
6036    * Whether the actor has the #ClutterActor:clip property set or not
6037    */
6038   obj_props[PROP_HAS_CLIP] =
6039     g_param_spec_boolean ("has-clip",
6040                           P_("Has Clip"),
6041                           P_("Whether the actor has a clip set"),
6042                           FALSE,
6043                           CLUTTER_PARAM_READABLE);
6044
6045   /**
6046    * ClutterActor:clip:
6047    *
6048    * The clip region for the actor, in actor-relative coordinates
6049    *
6050    * Every part of the actor outside the clip region will not be
6051    * painted
6052    */
6053   obj_props[PROP_CLIP] =
6054     g_param_spec_boxed ("clip",
6055                         P_("Clip"),
6056                         P_("The clip region for the actor"),
6057                         CLUTTER_TYPE_GEOMETRY,
6058                         CLUTTER_PARAM_READWRITE);
6059
6060   /**
6061    * ClutterActor:name:
6062    *
6063    * The name of the actor
6064    *
6065    * Since: 0.2
6066    */
6067   obj_props[PROP_NAME] =
6068     g_param_spec_string ("name",
6069                          P_("Name"),
6070                          P_("Name of the actor"),
6071                          NULL,
6072                          CLUTTER_PARAM_READWRITE);
6073
6074   /**
6075    * ClutterActor:scale-x:
6076    *
6077    * The horizontal scale of the actor.
6078    *
6079    * The #ClutterActor:scale-x property is animatable.
6080    *
6081    * Since: 0.6
6082    */
6083   obj_props[PROP_SCALE_X] =
6084     g_param_spec_double ("scale-x",
6085                          P_("Scale X"),
6086                          P_("Scale factor on the X axis"),
6087                          0.0, G_MAXDOUBLE,
6088                          1.0,
6089                          G_PARAM_READWRITE |
6090                          G_PARAM_STATIC_STRINGS |
6091                          CLUTTER_PARAM_ANIMATABLE);
6092
6093   /**
6094    * ClutterActor:scale-y:
6095    *
6096    * The vertical scale of the actor.
6097    *
6098    * The #ClutterActor:scale-y property is animatable.
6099    *
6100    * Since: 0.6
6101    */
6102   obj_props[PROP_SCALE_Y] =
6103     g_param_spec_double ("scale-y",
6104                          P_("Scale Y"),
6105                          P_("Scale factor on the Y axis"),
6106                          0.0, G_MAXDOUBLE,
6107                          1.0,
6108                          G_PARAM_READWRITE |
6109                          G_PARAM_STATIC_STRINGS |
6110                          CLUTTER_PARAM_ANIMATABLE);
6111
6112   /**
6113    * ClutterActor:scale-center-x:
6114    *
6115    * The horizontal center point for scaling
6116    *
6117    * Since: 1.0
6118    */
6119   obj_props[PROP_SCALE_CENTER_X] =
6120     g_param_spec_float ("scale-center-x",
6121                         P_("Scale Center X"),
6122                         P_("Horizontal scale center"),
6123                         -G_MAXFLOAT, G_MAXFLOAT,
6124                         0.0,
6125                         CLUTTER_PARAM_READWRITE);
6126
6127   /**
6128    * ClutterActor:scale-center-y:
6129    *
6130    * The vertical center point for scaling
6131    *
6132    * Since: 1.0
6133    */
6134   obj_props[PROP_SCALE_CENTER_Y] =
6135     g_param_spec_float ("scale-center-y",
6136                         P_("Scale Center Y"),
6137                         P_("Vertical scale center"),
6138                         -G_MAXFLOAT, G_MAXFLOAT,
6139                         0.0,
6140                         CLUTTER_PARAM_READWRITE);
6141
6142   /**
6143    * ClutterActor:scale-gravity:
6144    *
6145    * The center point for scaling expressed as a #ClutterGravity
6146    *
6147    * Since: 1.0
6148    */
6149   obj_props[PROP_SCALE_GRAVITY] =
6150     g_param_spec_enum ("scale-gravity",
6151                        P_("Scale Gravity"),
6152                        P_("The center of scaling"),
6153                        CLUTTER_TYPE_GRAVITY,
6154                        CLUTTER_GRAVITY_NONE,
6155                        CLUTTER_PARAM_READWRITE);
6156
6157   /**
6158    * ClutterActor:rotation-angle-x:
6159    *
6160    * The rotation angle on the X axis.
6161    *
6162    * The #ClutterActor:rotation-angle-x property is animatable.
6163    *
6164    * Since: 0.6
6165    */
6166   obj_props[PROP_ROTATION_ANGLE_X] =
6167     g_param_spec_double ("rotation-angle-x",
6168                          P_("Rotation Angle X"),
6169                          P_("The rotation angle on the X axis"),
6170                          -G_MAXDOUBLE, G_MAXDOUBLE,
6171                          0.0,
6172                          G_PARAM_READWRITE |
6173                          G_PARAM_STATIC_STRINGS |
6174                          CLUTTER_PARAM_ANIMATABLE);
6175
6176   /**
6177    * ClutterActor:rotation-angle-y:
6178    *
6179    * The rotation angle on the Y axis
6180    *
6181    * The #ClutterActor:rotation-angle-y property is animatable.
6182    *
6183    * Since: 0.6
6184    */
6185   obj_props[PROP_ROTATION_ANGLE_Y] =
6186     g_param_spec_double ("rotation-angle-y",
6187                          P_("Rotation Angle Y"),
6188                          P_("The rotation angle on the Y axis"),
6189                          -G_MAXDOUBLE, G_MAXDOUBLE,
6190                          0.0,
6191                          G_PARAM_READWRITE |
6192                          G_PARAM_STATIC_STRINGS |
6193                          CLUTTER_PARAM_ANIMATABLE);
6194
6195   /**
6196    * ClutterActor:rotation-angle-z:
6197    *
6198    * The rotation angle on the Z axis
6199    *
6200    * The #ClutterActor:rotation-angle-z property is animatable.
6201    *
6202    * Since: 0.6
6203    */
6204   obj_props[PROP_ROTATION_ANGLE_Z] =
6205     g_param_spec_double ("rotation-angle-z",
6206                          P_("Rotation Angle Z"),
6207                          P_("The rotation angle on the Z axis"),
6208                          -G_MAXDOUBLE, G_MAXDOUBLE,
6209                          0.0,
6210                          G_PARAM_READWRITE |
6211                          G_PARAM_STATIC_STRINGS |
6212                          CLUTTER_PARAM_ANIMATABLE);
6213
6214   /**
6215    * ClutterActor:rotation-center-x:
6216    *
6217    * The rotation center on the X axis.
6218    *
6219    * Since: 0.6
6220    */
6221   obj_props[PROP_ROTATION_CENTER_X] =
6222     g_param_spec_boxed ("rotation-center-x",
6223                         P_("Rotation Center X"),
6224                         P_("The rotation center on the X axis"),
6225                         CLUTTER_TYPE_VERTEX,
6226                         CLUTTER_PARAM_READWRITE);
6227
6228   /**
6229    * ClutterActor:rotation-center-y:
6230    *
6231    * The rotation center on the Y axis.
6232    *
6233    * Since: 0.6
6234    */
6235   obj_props[PROP_ROTATION_CENTER_Y] =
6236     g_param_spec_boxed ("rotation-center-y",
6237                         P_("Rotation Center Y"),
6238                         P_("The rotation center on the Y axis"),
6239                         CLUTTER_TYPE_VERTEX,
6240                         CLUTTER_PARAM_READWRITE);
6241
6242   /**
6243    * ClutterActor:rotation-center-z:
6244    *
6245    * The rotation center on the Z axis.
6246    *
6247    * Since: 0.6
6248    */
6249   obj_props[PROP_ROTATION_CENTER_Z] =
6250     g_param_spec_boxed ("rotation-center-z",
6251                         P_("Rotation Center Z"),
6252                         P_("The rotation center on the Z axis"),
6253                         CLUTTER_TYPE_VERTEX,
6254                         CLUTTER_PARAM_READWRITE);
6255
6256   /**
6257    * ClutterActor:rotation-center-z-gravity:
6258    *
6259    * The rotation center on the Z axis expressed as a #ClutterGravity.
6260    *
6261    * Since: 1.0
6262    */
6263   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6264     g_param_spec_enum ("rotation-center-z-gravity",
6265                        P_("Rotation Center Z Gravity"),
6266                        P_("Center point for rotation around the Z axis"),
6267                        CLUTTER_TYPE_GRAVITY,
6268                        CLUTTER_GRAVITY_NONE,
6269                        CLUTTER_PARAM_READWRITE);
6270
6271   /**
6272    * ClutterActor:anchor-x:
6273    *
6274    * The X coordinate of an actor's anchor point, relative to
6275    * the actor coordinate space, in pixels
6276    *
6277    * Since: 0.8
6278    */
6279   obj_props[PROP_ANCHOR_X] =
6280     g_param_spec_float ("anchor-x",
6281                         P_("Anchor X"),
6282                         P_("X coordinate of the anchor point"),
6283                         -G_MAXFLOAT, G_MAXFLOAT,
6284                         0,
6285                         CLUTTER_PARAM_READWRITE);
6286
6287   /**
6288    * ClutterActor:anchor-y:
6289    *
6290    * The Y coordinate of an actor's anchor point, relative to
6291    * the actor coordinate space, in pixels
6292    *
6293    * Since: 0.8
6294    */
6295   obj_props[PROP_ANCHOR_Y] =
6296     g_param_spec_float ("anchor-y",
6297                         P_("Anchor Y"),
6298                         P_("Y coordinate of the anchor point"),
6299                         -G_MAXFLOAT, G_MAXFLOAT,
6300                         0,
6301                         CLUTTER_PARAM_READWRITE);
6302
6303   /**
6304    * ClutterActor:anchor-gravity:
6305    *
6306    * The anchor point expressed as a #ClutterGravity
6307    *
6308    * Since: 1.0
6309    */
6310   obj_props[PROP_ANCHOR_GRAVITY] =
6311     g_param_spec_enum ("anchor-gravity",
6312                        P_("Anchor Gravity"),
6313                        P_("The anchor point as a ClutterGravity"),
6314                        CLUTTER_TYPE_GRAVITY,
6315                        CLUTTER_GRAVITY_NONE,
6316                        CLUTTER_PARAM_READWRITE);
6317
6318   /**
6319    * ClutterActor:show-on-set-parent:
6320    *
6321    * If %TRUE, the actor is automatically shown when parented.
6322    *
6323    * Calling clutter_actor_hide() on an actor which has not been
6324    * parented will set this property to %FALSE as a side effect.
6325    *
6326    * Since: 0.8
6327    */
6328   obj_props[PROP_SHOW_ON_SET_PARENT] =
6329     g_param_spec_boolean ("show-on-set-parent",
6330                           P_("Show on set parent"),
6331                           P_("Whether the actor is shown when parented"),
6332                           TRUE,
6333                           CLUTTER_PARAM_READWRITE);
6334
6335   /**
6336    * ClutterActor:clip-to-allocation:
6337    *
6338    * Whether the clip region should track the allocated area
6339    * of the actor.
6340    *
6341    * This property is ignored if a clip area has been explicitly
6342    * set using clutter_actor_set_clip().
6343    *
6344    * Since: 1.0
6345    */
6346   obj_props[PROP_CLIP_TO_ALLOCATION] =
6347     g_param_spec_boolean ("clip-to-allocation",
6348                           P_("Clip to Allocation"),
6349                           P_("Sets the clip region to track the actor's allocation"),
6350                           FALSE,
6351                           CLUTTER_PARAM_READWRITE);
6352
6353   /**
6354    * ClutterActor:text-direction:
6355    *
6356    * The direction of the text inside a #ClutterActor.
6357    *
6358    * Since: 1.0
6359    */
6360   obj_props[PROP_TEXT_DIRECTION] =
6361     g_param_spec_enum ("text-direction",
6362                        P_("Text Direction"),
6363                        P_("Direction of the text"),
6364                        CLUTTER_TYPE_TEXT_DIRECTION,
6365                        CLUTTER_TEXT_DIRECTION_LTR,
6366                        CLUTTER_PARAM_READWRITE);
6367
6368   /**
6369    * ClutterActor:has-pointer:
6370    *
6371    * Whether the actor contains the pointer of a #ClutterInputDevice
6372    * or not.
6373    *
6374    * Since: 1.2
6375    */
6376   obj_props[PROP_HAS_POINTER] =
6377     g_param_spec_boolean ("has-pointer",
6378                           P_("Has Pointer"),
6379                           P_("Whether the actor contains the pointer of an input device"),
6380                           FALSE,
6381                           CLUTTER_PARAM_READABLE);
6382
6383   /**
6384    * ClutterActor:actions:
6385    *
6386    * Adds a #ClutterAction to the actor
6387    *
6388    * Since: 1.4
6389    */
6390   obj_props[PROP_ACTIONS] =
6391     g_param_spec_object ("actions",
6392                          P_("Actions"),
6393                          P_("Adds an action to the actor"),
6394                          CLUTTER_TYPE_ACTION,
6395                          CLUTTER_PARAM_WRITABLE);
6396
6397   /**
6398    * ClutterActor:constraints:
6399    *
6400    * Adds a #ClutterConstraint to the actor
6401    *
6402    * Since: 1.4
6403    */
6404   obj_props[PROP_CONSTRAINTS] =
6405     g_param_spec_object ("constraints",
6406                          P_("Constraints"),
6407                          P_("Adds a constraint to the actor"),
6408                          CLUTTER_TYPE_CONSTRAINT,
6409                          CLUTTER_PARAM_WRITABLE);
6410
6411   /**
6412    * ClutterActor:effect:
6413    *
6414    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6415    *
6416    * Since: 1.4
6417    */
6418   obj_props[PROP_EFFECT] =
6419     g_param_spec_object ("effect",
6420                          P_("Effect"),
6421                          P_("Add an effect to be applied on the actor"),
6422                          CLUTTER_TYPE_EFFECT,
6423                          CLUTTER_PARAM_WRITABLE);
6424
6425   /**
6426    * ClutterActor:layout-manager:
6427    *
6428    * A delegate object for controlling the layout of the children of
6429    * an actor.
6430    *
6431    * Since: 1.10
6432    */
6433   obj_props[PROP_LAYOUT_MANAGER] =
6434     g_param_spec_object ("layout-manager",
6435                          P_("Layout Manager"),
6436                          P_("The object controlling the layout of an actor's children"),
6437                          CLUTTER_TYPE_LAYOUT_MANAGER,
6438                          CLUTTER_PARAM_READWRITE);
6439
6440   /**
6441    * ClutterActor:x-expand:
6442    *
6443    * Whether a layout manager should assign more space to the actor on
6444    * the X axis.
6445    *
6446    * Since: 1.12
6447    */
6448   obj_props[PROP_X_EXPAND] =
6449     g_param_spec_boolean ("x-expand",
6450                           P_("X Expand"),
6451                           P_("Whether extra horizontal space should be assigned to the actor"),
6452                           FALSE,
6453                           G_PARAM_READWRITE |
6454                           G_PARAM_STATIC_STRINGS);
6455
6456   /**
6457    * ClutterActor:y-expand:
6458    *
6459    * Whether a layout manager should assign more space to the actor on
6460    * the Y axis.
6461    *
6462    * Since: 1.12
6463    */
6464   obj_props[PROP_Y_EXPAND] =
6465     g_param_spec_boolean ("y-expand",
6466                           P_("Y Expand"),
6467                           P_("Whether extra vertical space should be assigned to the actor"),
6468                           FALSE,
6469                           G_PARAM_READWRITE |
6470                           G_PARAM_STATIC_STRINGS);
6471
6472   /**
6473    * ClutterActor:x-align:
6474    *
6475    * The alignment of an actor on the X axis, if the actor has been given
6476    * extra space for its allocation. See also the #ClutterActor:x-expand
6477    * property.
6478    *
6479    * Since: 1.10
6480    */
6481   obj_props[PROP_X_ALIGN] =
6482     g_param_spec_enum ("x-align",
6483                        P_("X Alignment"),
6484                        P_("The alignment of the actor on the X axis within its allocation"),
6485                        CLUTTER_TYPE_ACTOR_ALIGN,
6486                        CLUTTER_ACTOR_ALIGN_FILL,
6487                        CLUTTER_PARAM_READWRITE);
6488
6489   /**
6490    * ClutterActor:y-align:
6491    *
6492    * The alignment of an actor on the Y axis, if the actor has been given
6493    * extra space for its allocation.
6494    *
6495    * Since: 1.10
6496    */
6497   obj_props[PROP_Y_ALIGN] =
6498     g_param_spec_enum ("y-align",
6499                        P_("Y Alignment"),
6500                        P_("The alignment of the actor on the Y axis within its allocation"),
6501                        CLUTTER_TYPE_ACTOR_ALIGN,
6502                        CLUTTER_ACTOR_ALIGN_FILL,
6503                        CLUTTER_PARAM_READWRITE);
6504
6505   /**
6506    * ClutterActor:margin-top:
6507    *
6508    * The margin (in pixels) from the top of the actor.
6509    *
6510    * This property adds a margin to the actor's preferred size; the margin
6511    * will be automatically taken into account when allocating the actor.
6512    *
6513    * Since: 1.10
6514    */
6515   obj_props[PROP_MARGIN_TOP] =
6516     g_param_spec_float ("margin-top",
6517                         P_("Margin Top"),
6518                         P_("Extra space at the top"),
6519                         0.0, G_MAXFLOAT,
6520                         0.0,
6521                         CLUTTER_PARAM_READWRITE);
6522
6523   /**
6524    * ClutterActor:margin-bottom:
6525    *
6526    * The margin (in pixels) from the bottom of the actor.
6527    *
6528    * This property adds a margin to the actor's preferred size; the margin
6529    * will be automatically taken into account when allocating the actor.
6530    *
6531    * Since: 1.10
6532    */
6533   obj_props[PROP_MARGIN_BOTTOM] =
6534     g_param_spec_float ("margin-bottom",
6535                         P_("Margin Bottom"),
6536                         P_("Extra space at the bottom"),
6537                         0.0, G_MAXFLOAT,
6538                         0.0,
6539                         CLUTTER_PARAM_READWRITE);
6540
6541   /**
6542    * ClutterActor:margin-left:
6543    *
6544    * The margin (in pixels) from the left of the actor.
6545    *
6546    * This property adds a margin to the actor's preferred size; the margin
6547    * will be automatically taken into account when allocating the actor.
6548    *
6549    * Since: 1.10
6550    */
6551   obj_props[PROP_MARGIN_LEFT] =
6552     g_param_spec_float ("margin-left",
6553                         P_("Margin Left"),
6554                         P_("Extra space at the left"),
6555                         0.0, G_MAXFLOAT,
6556                         0.0,
6557                         CLUTTER_PARAM_READWRITE);
6558
6559   /**
6560    * ClutterActor:margin-right:
6561    *
6562    * The margin (in pixels) from the right of the actor.
6563    *
6564    * This property adds a margin to the actor's preferred size; the margin
6565    * will be automatically taken into account when allocating the actor.
6566    *
6567    * Since: 1.10
6568    */
6569   obj_props[PROP_MARGIN_RIGHT] =
6570     g_param_spec_float ("margin-right",
6571                         P_("Margin Right"),
6572                         P_("Extra space at the right"),
6573                         0.0, G_MAXFLOAT,
6574                         0.0,
6575                         CLUTTER_PARAM_READWRITE);
6576
6577   /**
6578    * ClutterActor:background-color-set:
6579    *
6580    * Whether the #ClutterActor:background-color property has been set.
6581    *
6582    * Since: 1.10
6583    */
6584   obj_props[PROP_BACKGROUND_COLOR_SET] =
6585     g_param_spec_boolean ("background-color-set",
6586                           P_("Background Color Set"),
6587                           P_("Whether the background color is set"),
6588                           FALSE,
6589                           CLUTTER_PARAM_READABLE);
6590
6591   /**
6592    * ClutterActor:background-color:
6593    *
6594    * Paints a solid fill of the actor's allocation using the specified
6595    * color.
6596    *
6597    * The #ClutterActor:background-color property is animatable.
6598    *
6599    * Since: 1.10
6600    */
6601   obj_props[PROP_BACKGROUND_COLOR] =
6602     clutter_param_spec_color ("background-color",
6603                               P_("Background color"),
6604                               P_("The actor's background color"),
6605                               CLUTTER_COLOR_Transparent,
6606                               G_PARAM_READWRITE |
6607                               G_PARAM_STATIC_STRINGS |
6608                               CLUTTER_PARAM_ANIMATABLE);
6609
6610   /**
6611    * ClutterActor:first-child:
6612    *
6613    * The actor's first child.
6614    *
6615    * Since: 1.10
6616    */
6617   obj_props[PROP_FIRST_CHILD] =
6618     g_param_spec_object ("first-child",
6619                          P_("First Child"),
6620                          P_("The actor's first child"),
6621                          CLUTTER_TYPE_ACTOR,
6622                          CLUTTER_PARAM_READABLE);
6623
6624   /**
6625    * ClutterActor:last-child:
6626    *
6627    * The actor's last child.
6628    *
6629    * Since: 1.10
6630    */
6631   obj_props[PROP_LAST_CHILD] =
6632     g_param_spec_object ("last-child",
6633                          P_("Last Child"),
6634                          P_("The actor's last child"),
6635                          CLUTTER_TYPE_ACTOR,
6636                          CLUTTER_PARAM_READABLE);
6637
6638   /**
6639    * ClutterActor:content:
6640    *
6641    * The #ClutterContent implementation that controls the content
6642    * of the actor.
6643    *
6644    * Since: 1.10
6645    */
6646   obj_props[PROP_CONTENT] =
6647     g_param_spec_object ("content",
6648                          P_("Content"),
6649                          P_("Delegate object for painting the actor's content"),
6650                          CLUTTER_TYPE_CONTENT,
6651                          CLUTTER_PARAM_READWRITE);
6652
6653   /**
6654    * ClutterActor:content-gravity:
6655    *
6656    * The alignment that should be honoured by the #ClutterContent
6657    * set with the #ClutterActor:content property.
6658    *
6659    * Changing the value of this property will change the bounding box of
6660    * the content; you can use the #ClutterActor:content-box property to
6661    * get the position and size of the content within the actor's
6662    * allocation.
6663    *
6664    * This property is meaningful only for #ClutterContent implementations
6665    * that have a preferred size, and if the preferred size is smaller than
6666    * the actor's allocation.
6667    *
6668    * The #ClutterActor:content-gravity property is animatable.
6669    *
6670    * Since: 1.10
6671    */
6672   obj_props[PROP_CONTENT_GRAVITY] =
6673     g_param_spec_enum ("content-gravity",
6674                        P_("Content Gravity"),
6675                        P_("Alignment of the actor's content"),
6676                        CLUTTER_TYPE_CONTENT_GRAVITY,
6677                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6678                        CLUTTER_PARAM_READWRITE);
6679
6680   /**
6681    * ClutterActor:content-box:
6682    *
6683    * The bounding box for the #ClutterContent used by the actor.
6684    *
6685    * The value of this property is controlled by the #ClutterActor:allocation
6686    * and #ClutterActor:content-gravity properties of #ClutterActor.
6687    *
6688    * The bounding box for the content is guaranteed to never exceed the
6689    * allocation's of the actor.
6690    *
6691    * Since: 1.10
6692    */
6693   obj_props[PROP_CONTENT_BOX] =
6694     g_param_spec_boxed ("content-box",
6695                         P_("Content Box"),
6696                         P_("The bounding box of the actor's content"),
6697                         CLUTTER_TYPE_ACTOR_BOX,
6698                         G_PARAM_READABLE |
6699                         G_PARAM_STATIC_STRINGS |
6700                         CLUTTER_PARAM_ANIMATABLE);
6701
6702   obj_props[PROP_MINIFICATION_FILTER] =
6703     g_param_spec_enum ("minification-filter",
6704                        P_("Minification Filter"),
6705                        P_("The filter used when reducing the size of the content"),
6706                        CLUTTER_TYPE_SCALING_FILTER,
6707                        CLUTTER_SCALING_FILTER_LINEAR,
6708                        CLUTTER_PARAM_READWRITE);
6709
6710   obj_props[PROP_MAGNIFICATION_FILTER] =
6711     g_param_spec_enum ("magnification-filter",
6712                        P_("Magnification Filter"),
6713                        P_("The filter used when increasing the size of the content"),
6714                        CLUTTER_TYPE_SCALING_FILTER,
6715                        CLUTTER_SCALING_FILTER_LINEAR,
6716                        CLUTTER_PARAM_READWRITE);
6717
6718   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6719
6720   /**
6721    * ClutterActor::destroy:
6722    * @actor: the #ClutterActor which emitted the signal
6723    *
6724    * The ::destroy signal notifies that all references held on the
6725    * actor which emitted it should be released.
6726    *
6727    * The ::destroy signal should be used by all holders of a reference
6728    * on @actor.
6729    *
6730    * This signal might result in the finalization of the #ClutterActor
6731    * if all references are released.
6732    *
6733    * Composite actors and actors implementing the #ClutterContainer
6734    * interface should override the default implementation of the
6735    * class handler of this signal and call clutter_actor_destroy() on
6736    * their children. When overriding the default class handler, it is
6737    * required to chain up to the parent's implementation.
6738    *
6739    * Since: 0.2
6740    */
6741   actor_signals[DESTROY] =
6742     g_signal_new (I_("destroy"),
6743                   G_TYPE_FROM_CLASS (object_class),
6744                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6745                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6746                   NULL, NULL,
6747                   _clutter_marshal_VOID__VOID,
6748                   G_TYPE_NONE, 0);
6749   /**
6750    * ClutterActor::show:
6751    * @actor: the object which received the signal
6752    *
6753    * The ::show signal is emitted when an actor is visible and
6754    * rendered on the stage.
6755    *
6756    * Since: 0.2
6757    */
6758   actor_signals[SHOW] =
6759     g_signal_new (I_("show"),
6760                   G_TYPE_FROM_CLASS (object_class),
6761                   G_SIGNAL_RUN_FIRST,
6762                   G_STRUCT_OFFSET (ClutterActorClass, show),
6763                   NULL, NULL,
6764                   _clutter_marshal_VOID__VOID,
6765                   G_TYPE_NONE, 0);
6766   /**
6767    * ClutterActor::hide:
6768    * @actor: the object which received the signal
6769    *
6770    * The ::hide signal is emitted when an actor is no longer rendered
6771    * on the stage.
6772    *
6773    * Since: 0.2
6774    */
6775   actor_signals[HIDE] =
6776     g_signal_new (I_("hide"),
6777                   G_TYPE_FROM_CLASS (object_class),
6778                   G_SIGNAL_RUN_FIRST,
6779                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6780                   NULL, NULL,
6781                   _clutter_marshal_VOID__VOID,
6782                   G_TYPE_NONE, 0);
6783   /**
6784    * ClutterActor::parent-set:
6785    * @actor: the object which received the signal
6786    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6787    *
6788    * This signal is emitted when the parent of the actor changes.
6789    *
6790    * Since: 0.2
6791    */
6792   actor_signals[PARENT_SET] =
6793     g_signal_new (I_("parent-set"),
6794                   G_TYPE_FROM_CLASS (object_class),
6795                   G_SIGNAL_RUN_LAST,
6796                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6797                   NULL, NULL,
6798                   _clutter_marshal_VOID__OBJECT,
6799                   G_TYPE_NONE, 1,
6800                   CLUTTER_TYPE_ACTOR);
6801
6802   /**
6803    * ClutterActor::queue-redraw:
6804    * @actor: the actor we're bubbling the redraw request through
6805    * @origin: the actor which initiated the redraw request
6806    *
6807    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6808    * is called on @origin.
6809    *
6810    * The default implementation for #ClutterActor chains up to the
6811    * parent actor and queues a redraw on the parent, thus "bubbling"
6812    * the redraw queue up through the actor graph. The default
6813    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6814    * in a main loop idle handler.
6815    *
6816    * Note that the @origin actor may be the stage, or a container; it
6817    * does not have to be a leaf node in the actor graph.
6818    *
6819    * Toolkits embedding a #ClutterStage which require a redraw and
6820    * relayout cycle can stop the emission of this signal using the
6821    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6822    * themselves, like:
6823    *
6824    * |[
6825    *   static void
6826    *   on_redraw_complete (gpointer data)
6827    *   {
6828    *     ClutterStage *stage = data;
6829    *
6830    *     /&ast; execute the Clutter drawing pipeline &ast;/
6831    *     clutter_stage_ensure_redraw (stage);
6832    *   }
6833    *
6834    *   static void
6835    *   on_stage_queue_redraw (ClutterStage *stage)
6836    *   {
6837    *     /&ast; this prevents the default handler to run &ast;/
6838    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6839    *
6840    *     /&ast; queue a redraw with the host toolkit and call
6841    *      &ast; a function when the redraw has been completed
6842    *      &ast;/
6843    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6844    *   }
6845    * ]|
6846    *
6847    * <note><para>This signal is emitted before the Clutter paint
6848    * pipeline is executed. If you want to know when the pipeline has
6849    * been completed you should connect to the ::paint signal on the
6850    * Stage with g_signal_connect_after().</para></note>
6851    *
6852    * Since: 1.0
6853    */
6854   actor_signals[QUEUE_REDRAW] =
6855     g_signal_new (I_("queue-redraw"),
6856                   G_TYPE_FROM_CLASS (object_class),
6857                   G_SIGNAL_RUN_LAST |
6858                   G_SIGNAL_NO_HOOKS,
6859                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6860                   NULL, NULL,
6861                   _clutter_marshal_VOID__OBJECT,
6862                   G_TYPE_NONE, 1,
6863                   CLUTTER_TYPE_ACTOR);
6864
6865   /**
6866    * ClutterActor::queue-relayout
6867    * @actor: the actor being queued for relayout
6868    *
6869    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6870    * is called on an actor.
6871    *
6872    * The default implementation for #ClutterActor chains up to the
6873    * parent actor and queues a relayout on the parent, thus "bubbling"
6874    * the relayout queue up through the actor graph.
6875    *
6876    * The main purpose of this signal is to allow relayout to be propagated
6877    * properly in the procense of #ClutterClone actors. Applications will
6878    * not normally need to connect to this signal.
6879    *
6880    * Since: 1.2
6881    */
6882   actor_signals[QUEUE_RELAYOUT] =
6883     g_signal_new (I_("queue-relayout"),
6884                   G_TYPE_FROM_CLASS (object_class),
6885                   G_SIGNAL_RUN_LAST |
6886                   G_SIGNAL_NO_HOOKS,
6887                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6888                   NULL, NULL,
6889                   _clutter_marshal_VOID__VOID,
6890                   G_TYPE_NONE, 0);
6891
6892   /**
6893    * ClutterActor::event:
6894    * @actor: the actor which received the event
6895    * @event: a #ClutterEvent
6896    *
6897    * The ::event signal is emitted each time an event is received
6898    * by the @actor. This signal will be emitted on every actor,
6899    * following the hierarchy chain, until it reaches the top-level
6900    * container (the #ClutterStage).
6901    *
6902    * Return value: %TRUE if the event has been handled by the actor,
6903    *   or %FALSE to continue the emission.
6904    *
6905    * Since: 0.6
6906    */
6907   actor_signals[EVENT] =
6908     g_signal_new (I_("event"),
6909                   G_TYPE_FROM_CLASS (object_class),
6910                   G_SIGNAL_RUN_LAST,
6911                   G_STRUCT_OFFSET (ClutterActorClass, event),
6912                   _clutter_boolean_handled_accumulator, NULL,
6913                   _clutter_marshal_BOOLEAN__BOXED,
6914                   G_TYPE_BOOLEAN, 1,
6915                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6916   /**
6917    * ClutterActor::button-press-event:
6918    * @actor: the actor which received the event
6919    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6920    *
6921    * The ::button-press-event signal is emitted each time a mouse button
6922    * is pressed on @actor.
6923    *
6924    * Return value: %TRUE if the event has been handled by the actor,
6925    *   or %FALSE to continue the emission.
6926    *
6927    * Since: 0.6
6928    */
6929   actor_signals[BUTTON_PRESS_EVENT] =
6930     g_signal_new (I_("button-press-event"),
6931                   G_TYPE_FROM_CLASS (object_class),
6932                   G_SIGNAL_RUN_LAST,
6933                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6934                   _clutter_boolean_handled_accumulator, NULL,
6935                   _clutter_marshal_BOOLEAN__BOXED,
6936                   G_TYPE_BOOLEAN, 1,
6937                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6938   /**
6939    * ClutterActor::button-release-event:
6940    * @actor: the actor which received the event
6941    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6942    *
6943    * The ::button-release-event signal is emitted each time a mouse button
6944    * is released on @actor.
6945    *
6946    * Return value: %TRUE if the event has been handled by the actor,
6947    *   or %FALSE to continue the emission.
6948    *
6949    * Since: 0.6
6950    */
6951   actor_signals[BUTTON_RELEASE_EVENT] =
6952     g_signal_new (I_("button-release-event"),
6953                   G_TYPE_FROM_CLASS (object_class),
6954                   G_SIGNAL_RUN_LAST,
6955                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6956                   _clutter_boolean_handled_accumulator, NULL,
6957                   _clutter_marshal_BOOLEAN__BOXED,
6958                   G_TYPE_BOOLEAN, 1,
6959                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6960   /**
6961    * ClutterActor::scroll-event:
6962    * @actor: the actor which received the event
6963    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6964    *
6965    * The ::scroll-event signal is emitted each time the mouse is
6966    * scrolled on @actor
6967    *
6968    * Return value: %TRUE if the event has been handled by the actor,
6969    *   or %FALSE to continue the emission.
6970    *
6971    * Since: 0.6
6972    */
6973   actor_signals[SCROLL_EVENT] =
6974     g_signal_new (I_("scroll-event"),
6975                   G_TYPE_FROM_CLASS (object_class),
6976                   G_SIGNAL_RUN_LAST,
6977                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6978                   _clutter_boolean_handled_accumulator, NULL,
6979                   _clutter_marshal_BOOLEAN__BOXED,
6980                   G_TYPE_BOOLEAN, 1,
6981                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6982   /**
6983    * ClutterActor::key-press-event:
6984    * @actor: the actor which received the event
6985    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6986    *
6987    * The ::key-press-event signal is emitted each time a keyboard button
6988    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6989    *
6990    * Return value: %TRUE if the event has been handled by the actor,
6991    *   or %FALSE to continue the emission.
6992    *
6993    * Since: 0.6
6994    */
6995   actor_signals[KEY_PRESS_EVENT] =
6996     g_signal_new (I_("key-press-event"),
6997                   G_TYPE_FROM_CLASS (object_class),
6998                   G_SIGNAL_RUN_LAST,
6999                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7000                   _clutter_boolean_handled_accumulator, NULL,
7001                   _clutter_marshal_BOOLEAN__BOXED,
7002                   G_TYPE_BOOLEAN, 1,
7003                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7004   /**
7005    * ClutterActor::key-release-event:
7006    * @actor: the actor which received the event
7007    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7008    *
7009    * The ::key-release-event signal is emitted each time a keyboard button
7010    * is released while @actor has key focus (see
7011    * clutter_stage_set_key_focus()).
7012    *
7013    * Return value: %TRUE if the event has been handled by the actor,
7014    *   or %FALSE to continue the emission.
7015    *
7016    * Since: 0.6
7017    */
7018   actor_signals[KEY_RELEASE_EVENT] =
7019     g_signal_new (I_("key-release-event"),
7020                   G_TYPE_FROM_CLASS (object_class),
7021                   G_SIGNAL_RUN_LAST,
7022                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7023                   _clutter_boolean_handled_accumulator, NULL,
7024                   _clutter_marshal_BOOLEAN__BOXED,
7025                   G_TYPE_BOOLEAN, 1,
7026                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7027   /**
7028    * ClutterActor::motion-event:
7029    * @actor: the actor which received the event
7030    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7031    *
7032    * The ::motion-event signal is emitted each time the mouse pointer is
7033    * moved over @actor.
7034    *
7035    * Return value: %TRUE if the event has been handled by the actor,
7036    *   or %FALSE to continue the emission.
7037    *
7038    * Since: 0.6
7039    */
7040   actor_signals[MOTION_EVENT] =
7041     g_signal_new (I_("motion-event"),
7042                   G_TYPE_FROM_CLASS (object_class),
7043                   G_SIGNAL_RUN_LAST,
7044                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7045                   _clutter_boolean_handled_accumulator, NULL,
7046                   _clutter_marshal_BOOLEAN__BOXED,
7047                   G_TYPE_BOOLEAN, 1,
7048                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7049
7050   /**
7051    * ClutterActor::key-focus-in:
7052    * @actor: the actor which now has key focus
7053    *
7054    * The ::key-focus-in signal is emitted when @actor receives key focus.
7055    *
7056    * Since: 0.6
7057    */
7058   actor_signals[KEY_FOCUS_IN] =
7059     g_signal_new (I_("key-focus-in"),
7060                   G_TYPE_FROM_CLASS (object_class),
7061                   G_SIGNAL_RUN_LAST,
7062                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7063                   NULL, NULL,
7064                   _clutter_marshal_VOID__VOID,
7065                   G_TYPE_NONE, 0);
7066
7067   /**
7068    * ClutterActor::key-focus-out:
7069    * @actor: the actor which now has key focus
7070    *
7071    * The ::key-focus-out signal is emitted when @actor loses key focus.
7072    *
7073    * Since: 0.6
7074    */
7075   actor_signals[KEY_FOCUS_OUT] =
7076     g_signal_new (I_("key-focus-out"),
7077                   G_TYPE_FROM_CLASS (object_class),
7078                   G_SIGNAL_RUN_LAST,
7079                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7080                   NULL, NULL,
7081                   _clutter_marshal_VOID__VOID,
7082                   G_TYPE_NONE, 0);
7083
7084   /**
7085    * ClutterActor::enter-event:
7086    * @actor: the actor which the pointer has entered.
7087    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7088    *
7089    * The ::enter-event signal is emitted when the pointer enters the @actor
7090    *
7091    * Return value: %TRUE if the event has been handled by the actor,
7092    *   or %FALSE to continue the emission.
7093    *
7094    * Since: 0.6
7095    */
7096   actor_signals[ENTER_EVENT] =
7097     g_signal_new (I_("enter-event"),
7098                   G_TYPE_FROM_CLASS (object_class),
7099                   G_SIGNAL_RUN_LAST,
7100                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7101                   _clutter_boolean_handled_accumulator, NULL,
7102                   _clutter_marshal_BOOLEAN__BOXED,
7103                   G_TYPE_BOOLEAN, 1,
7104                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7105
7106   /**
7107    * ClutterActor::leave-event:
7108    * @actor: the actor which the pointer has left
7109    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7110    *
7111    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7112    *
7113    * Return value: %TRUE if the event has been handled by the actor,
7114    *   or %FALSE to continue the emission.
7115    *
7116    * Since: 0.6
7117    */
7118   actor_signals[LEAVE_EVENT] =
7119     g_signal_new (I_("leave-event"),
7120                   G_TYPE_FROM_CLASS (object_class),
7121                   G_SIGNAL_RUN_LAST,
7122                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7123                   _clutter_boolean_handled_accumulator, NULL,
7124                   _clutter_marshal_BOOLEAN__BOXED,
7125                   G_TYPE_BOOLEAN, 1,
7126                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7127
7128   /**
7129    * ClutterActor::captured-event:
7130    * @actor: the actor which received the signal
7131    * @event: a #ClutterEvent
7132    *
7133    * The ::captured-event signal is emitted when an event is captured
7134    * by Clutter. This signal will be emitted starting from the top-level
7135    * container (the #ClutterStage) to the actor which received the event
7136    * going down the hierarchy. This signal can be used to intercept every
7137    * event before the specialized events (like
7138    * ClutterActor::button-press-event or ::key-released-event) are
7139    * emitted.
7140    *
7141    * Return value: %TRUE if the event has been handled by the actor,
7142    *   or %FALSE to continue the emission.
7143    *
7144    * Since: 0.6
7145    */
7146   actor_signals[CAPTURED_EVENT] =
7147     g_signal_new (I_("captured-event"),
7148                   G_TYPE_FROM_CLASS (object_class),
7149                   G_SIGNAL_RUN_LAST,
7150                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7151                   _clutter_boolean_handled_accumulator, NULL,
7152                   _clutter_marshal_BOOLEAN__BOXED,
7153                   G_TYPE_BOOLEAN, 1,
7154                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7155
7156   /**
7157    * ClutterActor::paint:
7158    * @actor: the #ClutterActor that received the signal
7159    *
7160    * The ::paint signal is emitted each time an actor is being painted.
7161    *
7162    * Subclasses of #ClutterActor should override the class signal handler
7163    * and paint themselves in that function.
7164    *
7165    * It is possible to connect a handler to the ::paint signal in order
7166    * to set up some custom aspect of a paint.
7167    *
7168    * Since: 0.8
7169    */
7170   actor_signals[PAINT] =
7171     g_signal_new (I_("paint"),
7172                   G_TYPE_FROM_CLASS (object_class),
7173                   G_SIGNAL_RUN_LAST |
7174                   G_SIGNAL_NO_HOOKS,
7175                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7176                   NULL, NULL,
7177                   _clutter_marshal_VOID__VOID,
7178                   G_TYPE_NONE, 0);
7179   /**
7180    * ClutterActor::realize:
7181    * @actor: the #ClutterActor that received the signal
7182    *
7183    * The ::realize signal is emitted each time an actor is being
7184    * realized.
7185    *
7186    * Since: 0.8
7187    */
7188   actor_signals[REALIZE] =
7189     g_signal_new (I_("realize"),
7190                   G_TYPE_FROM_CLASS (object_class),
7191                   G_SIGNAL_RUN_LAST,
7192                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7193                   NULL, NULL,
7194                   _clutter_marshal_VOID__VOID,
7195                   G_TYPE_NONE, 0);
7196   /**
7197    * ClutterActor::unrealize:
7198    * @actor: the #ClutterActor that received the signal
7199    *
7200    * The ::unrealize signal is emitted each time an actor is being
7201    * unrealized.
7202    *
7203    * Since: 0.8
7204    */
7205   actor_signals[UNREALIZE] =
7206     g_signal_new (I_("unrealize"),
7207                   G_TYPE_FROM_CLASS (object_class),
7208                   G_SIGNAL_RUN_LAST,
7209                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7210                   NULL, NULL,
7211                   _clutter_marshal_VOID__VOID,
7212                   G_TYPE_NONE, 0);
7213
7214   /**
7215    * ClutterActor::pick:
7216    * @actor: the #ClutterActor that received the signal
7217    * @color: the #ClutterColor to be used when picking
7218    *
7219    * The ::pick signal is emitted each time an actor is being painted
7220    * in "pick mode". The pick mode is used to identify the actor during
7221    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7222    * The actor should paint its shape using the passed @pick_color.
7223    *
7224    * Subclasses of #ClutterActor should override the class signal handler
7225    * and paint themselves in that function.
7226    *
7227    * It is possible to connect a handler to the ::pick signal in order
7228    * to set up some custom aspect of a paint in pick mode.
7229    *
7230    * Since: 1.0
7231    */
7232   actor_signals[PICK] =
7233     g_signal_new (I_("pick"),
7234                   G_TYPE_FROM_CLASS (object_class),
7235                   G_SIGNAL_RUN_LAST,
7236                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7237                   NULL, NULL,
7238                   _clutter_marshal_VOID__BOXED,
7239                   G_TYPE_NONE, 1,
7240                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7241
7242   /**
7243    * ClutterActor::allocation-changed:
7244    * @actor: the #ClutterActor that emitted the signal
7245    * @box: a #ClutterActorBox with the new allocation
7246    * @flags: #ClutterAllocationFlags for the allocation
7247    *
7248    * The ::allocation-changed signal is emitted when the
7249    * #ClutterActor:allocation property changes. Usually, application
7250    * code should just use the notifications for the :allocation property
7251    * but if you want to track the allocation flags as well, for instance
7252    * to know whether the absolute origin of @actor changed, then you might
7253    * want use this signal instead.
7254    *
7255    * Since: 1.0
7256    */
7257   actor_signals[ALLOCATION_CHANGED] =
7258     g_signal_new (I_("allocation-changed"),
7259                   G_TYPE_FROM_CLASS (object_class),
7260                   G_SIGNAL_RUN_LAST,
7261                   0,
7262                   NULL, NULL,
7263                   _clutter_marshal_VOID__BOXED_FLAGS,
7264                   G_TYPE_NONE, 2,
7265                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7266                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7267
7268   /**
7269    * ClutterActor::transitions-completed:
7270    * @actor: a #ClutterActor
7271    *
7272    * The ::transitions-completed signal is emitted once all transitions
7273    * involving @actor are complete.
7274    *
7275    * Since: 1.10
7276    */
7277   actor_signals[TRANSITIONS_COMPLETED] =
7278     g_signal_new (I_("transitions-completed"),
7279                   G_TYPE_FROM_CLASS (object_class),
7280                   G_SIGNAL_RUN_LAST,
7281                   0,
7282                   NULL, NULL,
7283                   _clutter_marshal_VOID__VOID,
7284                   G_TYPE_NONE, 0);
7285 }
7286
7287 static void
7288 clutter_actor_init (ClutterActor *self)
7289 {
7290   ClutterActorPrivate *priv;
7291
7292   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7293
7294   priv->id = _clutter_context_acquire_id (self);
7295   priv->pick_id = -1;
7296
7297   priv->opacity = 0xff;
7298   priv->show_on_set_parent = TRUE;
7299
7300   priv->needs_width_request = TRUE;
7301   priv->needs_height_request = TRUE;
7302   priv->needs_allocation = TRUE;
7303
7304   priv->cached_width_age = 1;
7305   priv->cached_height_age = 1;
7306
7307   priv->opacity_override = -1;
7308   priv->enable_model_view_transform = TRUE;
7309
7310   /* Initialize an empty paint volume to start with */
7311   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7312   priv->last_paint_volume_valid = TRUE;
7313
7314   priv->transform_valid = FALSE;
7315
7316   /* the default is to stretch the content, to match the
7317    * current behaviour of basically all actors. also, it's
7318    * the easiest thing to compute.
7319    */
7320   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7321   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7322   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7323
7324   /* this flag will be set to TRUE if the actor gets a child
7325    * or if the [xy]-expand flags are explicitly set; until
7326    * then, the actor does not need to expand.
7327    *
7328    * this also allows us to avoid computing the expand flag
7329    * when building up a scene.
7330    */
7331   priv->needs_compute_expand = FALSE;
7332 }
7333
7334 /**
7335  * clutter_actor_new:
7336  *
7337  * Creates a new #ClutterActor.
7338  *
7339  * A newly created actor has a floating reference, which will be sunk
7340  * when it is added to another actor.
7341  *
7342  * Return value: (transfer full): the newly created #ClutterActor
7343  *
7344  * Since: 1.10
7345  */
7346 ClutterActor *
7347 clutter_actor_new (void)
7348 {
7349   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7350 }
7351
7352 /**
7353  * clutter_actor_destroy:
7354  * @self: a #ClutterActor
7355  *
7356  * Destroys an actor.  When an actor is destroyed, it will break any
7357  * references it holds to other objects.  If the actor is inside a
7358  * container, the actor will be removed.
7359  *
7360  * When you destroy a container, its children will be destroyed as well.
7361  *
7362  * Note: you cannot destroy the #ClutterStage returned by
7363  * clutter_stage_get_default().
7364  */
7365 void
7366 clutter_actor_destroy (ClutterActor *self)
7367 {
7368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7369
7370   g_object_ref (self);
7371
7372   /* avoid recursion while destroying */
7373   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7374     {
7375       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7376
7377       g_object_run_dispose (G_OBJECT (self));
7378
7379       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7380     }
7381
7382   g_object_unref (self);
7383 }
7384
7385 void
7386 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7387                                     ClutterPaintVolume *clip)
7388 {
7389   ClutterActorPrivate *priv = self->priv;
7390   ClutterPaintVolume *pv;
7391   gboolean clipped;
7392
7393   /* Remove queue entry early in the process, otherwise a new
7394      queue_redraw() during signal handling could put back this
7395      object in the stage redraw list (but the entry is freed as
7396      soon as we return from this function, causing a segfault
7397      later)
7398   */
7399   priv->queue_redraw_entry = NULL;
7400
7401   /* If we've been explicitly passed a clip volume then there's
7402    * nothing more to calculate, but otherwise the only thing we know
7403    * is that the change is constrained to the given actor.
7404    *
7405    * The idea is that if we know the paint volume for where the actor
7406    * was last drawn (in eye coordinates) and we also have the paint
7407    * volume for where it will be drawn next (in actor coordinates)
7408    * then if we queue a redraw for both these volumes that will cover
7409    * everything that needs to be redrawn to clear the old view and
7410    * show the latest view of the actor.
7411    *
7412    * Don't clip this redraw if we don't know what position we had for
7413    * the previous redraw since we don't know where to set the clip so
7414    * it will clear the actor as it is currently.
7415    */
7416   if (clip)
7417     {
7418       _clutter_actor_set_queue_redraw_clip (self, clip);
7419       clipped = TRUE;
7420     }
7421   else if (G_LIKELY (priv->last_paint_volume_valid))
7422     {
7423       pv = _clutter_actor_get_paint_volume_mutable (self);
7424       if (pv)
7425         {
7426           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7427
7428           /* make sure we redraw the actors old position... */
7429           _clutter_actor_set_queue_redraw_clip (stage,
7430                                                 &priv->last_paint_volume);
7431           _clutter_actor_signal_queue_redraw (stage, stage);
7432           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7433
7434           /* XXX: Ideally the redraw signal would take a clip volume
7435            * argument, but that would be an ABI break. Until we can
7436            * break the ABI we pass the argument out-of-band
7437            */
7438
7439           /* setup the clip for the actors new position... */
7440           _clutter_actor_set_queue_redraw_clip (self, pv);
7441           clipped = TRUE;
7442         }
7443       else
7444         clipped = FALSE;
7445     }
7446   else
7447     clipped = FALSE;
7448
7449   _clutter_actor_signal_queue_redraw (self, self);
7450
7451   /* Just in case anyone is manually firing redraw signals without
7452    * using the public queue_redraw() API we are careful to ensure that
7453    * our out-of-band clip member is cleared before returning...
7454    *
7455    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7456    */
7457   if (G_LIKELY (clipped))
7458     _clutter_actor_set_queue_redraw_clip (self, NULL);
7459 }
7460
7461 static void
7462 _clutter_actor_get_allocation_clip (ClutterActor *self,
7463                                     ClutterActorBox *clip)
7464 {
7465   ClutterActorBox allocation;
7466
7467   /* XXX: we don't care if we get an out of date allocation here
7468    * because clutter_actor_queue_redraw_with_clip knows to ignore
7469    * the clip if the actor's allocation is invalid.
7470    *
7471    * This is noted because clutter_actor_get_allocation_box does some
7472    * unnecessary work to support buggy code with a comment suggesting
7473    * that it could be changed later which would be good for this use
7474    * case!
7475    */
7476   clutter_actor_get_allocation_box (self, &allocation);
7477
7478   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7479    * actor's own coordinate space but the allocation is in parent
7480    * coordinates */
7481   clip->x1 = 0;
7482   clip->y1 = 0;
7483   clip->x2 = allocation.x2 - allocation.x1;
7484   clip->y2 = allocation.y2 - allocation.y1;
7485 }
7486
7487 void
7488 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7489                                   ClutterRedrawFlags  flags,
7490                                   ClutterPaintVolume *volume,
7491                                   ClutterEffect      *effect)
7492 {
7493   ClutterActorPrivate *priv = self->priv;
7494   ClutterPaintVolume allocation_pv;
7495   ClutterPaintVolume *pv;
7496   gboolean should_free_pv;
7497   ClutterActor *stage;
7498
7499   /* Here's an outline of the actor queue redraw mechanism:
7500    *
7501    * The process starts in one of the following two functions which
7502    * are wrappers for this function:
7503    * clutter_actor_queue_redraw
7504    * _clutter_actor_queue_redraw_with_clip
7505    *
7506    * additionally, an effect can queue a redraw by wrapping this
7507    * function in clutter_effect_queue_rerun
7508    *
7509    * This functions queues an entry in a list associated with the
7510    * stage which is a list of actors that queued a redraw while
7511    * updating the timelines, performing layouting and processing other
7512    * mainloop sources before the next paint starts.
7513    *
7514    * We aim to minimize the processing done at this point because
7515    * there is a good chance other events will happen while updating
7516    * the scenegraph that would invalidate any expensive work we might
7517    * otherwise try to do here. For example we don't try and resolve
7518    * the screen space bounding box of an actor at this stage so as to
7519    * minimize how much of the screen redraw because it's possible
7520    * something else will happen which will force a full redraw anyway.
7521    *
7522    * When all updates are complete and we come to paint the stage then
7523    * we iterate this list and actually emit the "queue-redraw" signals
7524    * for each of the listed actors which will bubble up to the stage
7525    * for each actor and at that point we will transform the actors
7526    * paint volume into screen coordinates to determine the clip region
7527    * for what needs to be redrawn in the next paint.
7528    *
7529    * Besides minimizing redundant work another reason for this
7530    * deferred design is that it's more likely we will be able to
7531    * determine the paint volume of an actor once we've finished
7532    * updating the scenegraph because its allocation should be up to
7533    * date. NB: If we can't determine an actors paint volume then we
7534    * can't automatically queue a clipped redraw which can make a big
7535    * difference to performance.
7536    *
7537    * So the control flow goes like this:
7538    * One of clutter_actor_queue_redraw,
7539    *        _clutter_actor_queue_redraw_with_clip
7540    *     or clutter_effect_queue_rerun
7541    *
7542    * then control moves to:
7543    *   _clutter_stage_queue_actor_redraw
7544    *
7545    * later during _clutter_stage_do_update, once relayouting is done
7546    * and the scenegraph has been updated we will call:
7547    * _clutter_stage_finish_queue_redraws
7548    *
7549    * _clutter_stage_finish_queue_redraws will call
7550    * _clutter_actor_finish_queue_redraw for each listed actor.
7551    * Note: actors *are* allowed to queue further redraws during this
7552    * process (considering clone actors or texture_new_from_actor which
7553    * respond to their source queueing a redraw by queuing a redraw
7554    * themselves). We repeat the process until the list is empty.
7555    *
7556    * This will result in the "queue-redraw" signal being fired for
7557    * each actor which will pass control to the default signal handler:
7558    * clutter_actor_real_queue_redraw
7559    *
7560    * This will bubble up to the stages handler:
7561    * clutter_stage_real_queue_redraw
7562    *
7563    * clutter_stage_real_queue_redraw will transform the actors paint
7564    * volume into screen space and add it as a clip region for the next
7565    * paint.
7566    */
7567
7568   /* ignore queueing a redraw for actors being destroyed */
7569   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7570     return;
7571
7572   stage = _clutter_actor_get_stage_internal (self);
7573
7574   /* Ignore queueing a redraw for actors not descended from a stage */
7575   if (stage == NULL)
7576     return;
7577
7578   /* ignore queueing a redraw on stages that are being destroyed */
7579   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7580     return;
7581
7582   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7583     {
7584       ClutterActorBox allocation_clip;
7585       ClutterVertex origin;
7586
7587       /* If the actor doesn't have a valid allocation then we will
7588        * queue a full stage redraw. */
7589       if (priv->needs_allocation)
7590         {
7591           /* NB: NULL denotes an undefined clip which will result in a
7592            * full redraw... */
7593           _clutter_actor_set_queue_redraw_clip (self, NULL);
7594           _clutter_actor_signal_queue_redraw (self, self);
7595           return;
7596         }
7597
7598       _clutter_paint_volume_init_static (&allocation_pv, self);
7599       pv = &allocation_pv;
7600
7601       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7602
7603       origin.x = allocation_clip.x1;
7604       origin.y = allocation_clip.y1;
7605       origin.z = 0;
7606       clutter_paint_volume_set_origin (pv, &origin);
7607       clutter_paint_volume_set_width (pv,
7608                                       allocation_clip.x2 - allocation_clip.x1);
7609       clutter_paint_volume_set_height (pv,
7610                                        allocation_clip.y2 -
7611                                        allocation_clip.y1);
7612       should_free_pv = TRUE;
7613     }
7614   else
7615     {
7616       pv = volume;
7617       should_free_pv = FALSE;
7618     }
7619
7620   self->priv->queue_redraw_entry =
7621     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7622                                        priv->queue_redraw_entry,
7623                                        self,
7624                                        pv);
7625
7626   if (should_free_pv)
7627     clutter_paint_volume_free (pv);
7628
7629   /* If this is the first redraw queued then we can directly use the
7630      effect parameter */
7631   if (!priv->is_dirty)
7632     priv->effect_to_redraw = effect;
7633   /* Otherwise we need to merge it with the existing effect parameter */
7634   else if (effect != NULL)
7635     {
7636       /* If there's already an effect then we need to use whichever is
7637          later in the chain of actors. Otherwise a full redraw has
7638          already been queued on the actor so we need to ignore the
7639          effect parameter */
7640       if (priv->effect_to_redraw != NULL)
7641         {
7642           if (priv->effects == NULL)
7643             g_warning ("Redraw queued with an effect that is "
7644                        "not applied to the actor");
7645           else
7646             {
7647               const GList *l;
7648
7649               for (l = _clutter_meta_group_peek_metas (priv->effects);
7650                    l != NULL;
7651                    l = l->next)
7652                 {
7653                   if (l->data == priv->effect_to_redraw ||
7654                       l->data == effect)
7655                     priv->effect_to_redraw = l->data;
7656                 }
7657             }
7658         }
7659     }
7660   else
7661     {
7662       /* If no effect is specified then we need to redraw the whole
7663          actor */
7664       priv->effect_to_redraw = NULL;
7665     }
7666
7667   priv->is_dirty = TRUE;
7668 }
7669
7670 /**
7671  * clutter_actor_queue_redraw:
7672  * @self: A #ClutterActor
7673  *
7674  * Queues up a redraw of an actor and any children. The redraw occurs
7675  * once the main loop becomes idle (after the current batch of events
7676  * has been processed, roughly).
7677  *
7678  * Applications rarely need to call this, as redraws are handled
7679  * automatically by modification functions.
7680  *
7681  * This function will not do anything if @self is not visible, or
7682  * if the actor is inside an invisible part of the scenegraph.
7683  *
7684  * Also be aware that painting is a NOP for actors with an opacity of
7685  * 0
7686  *
7687  * When you are implementing a custom actor you must queue a redraw
7688  * whenever some private state changes that will affect painting or
7689  * picking of your actor.
7690  */
7691 void
7692 clutter_actor_queue_redraw (ClutterActor *self)
7693 {
7694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7695
7696   _clutter_actor_queue_redraw_full (self,
7697                                     0, /* flags */
7698                                     NULL, /* clip volume */
7699                                     NULL /* effect */);
7700 }
7701
7702 /*< private >
7703  * _clutter_actor_queue_redraw_with_clip:
7704  * @self: A #ClutterActor
7705  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7706  *   this queue redraw.
7707  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7708  *   redrawn or %NULL if you are just using a @flag to state your
7709  *   desired clipping.
7710  *
7711  * Queues up a clipped redraw of an actor and any children. The redraw
7712  * occurs once the main loop becomes idle (after the current batch of
7713  * events has been processed, roughly).
7714  *
7715  * If no flags are given the clip volume is defined by @volume
7716  * specified in actor coordinates and tells Clutter that only content
7717  * within this volume has been changed so Clutter can optionally
7718  * optimize the redraw.
7719  *
7720  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7721  * should be %NULL and this tells Clutter to use the actor's current
7722  * allocation as a clip box. This flag can only be used for 2D actors,
7723  * because any actor with depth may be projected outside its
7724  * allocation.
7725  *
7726  * Applications rarely need to call this, as redraws are handled
7727  * automatically by modification functions.
7728  *
7729  * This function will not do anything if @self is not visible, or if
7730  * the actor is inside an invisible part of the scenegraph.
7731  *
7732  * Also be aware that painting is a NOP for actors with an opacity of
7733  * 0
7734  *
7735  * When you are implementing a custom actor you must queue a redraw
7736  * whenever some private state changes that will affect painting or
7737  * picking of your actor.
7738  */
7739 void
7740 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7741                                        ClutterRedrawFlags  flags,
7742                                        ClutterPaintVolume *volume)
7743 {
7744   _clutter_actor_queue_redraw_full (self,
7745                                     flags, /* flags */
7746                                     volume, /* clip volume */
7747                                     NULL /* effect */);
7748 }
7749
7750 static void
7751 _clutter_actor_queue_only_relayout (ClutterActor *self)
7752 {
7753   ClutterActorPrivate *priv = self->priv;
7754
7755   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7756     return;
7757
7758   if (priv->needs_width_request &&
7759       priv->needs_height_request &&
7760       priv->needs_allocation)
7761     return; /* save some cpu cycles */
7762
7763 #if CLUTTER_ENABLE_DEBUG
7764   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7765     {
7766       g_warning ("The actor '%s' is currently inside an allocation "
7767                  "cycle; calling clutter_actor_queue_relayout() is "
7768                  "not recommended",
7769                  _clutter_actor_get_debug_name (self));
7770     }
7771 #endif /* CLUTTER_ENABLE_DEBUG */
7772
7773   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7774 }
7775
7776 /**
7777  * clutter_actor_queue_redraw_with_clip:
7778  * @self: a #ClutterActor
7779  * @clip: (allow-none): a rectangular clip region, or %NULL
7780  *
7781  * Queues a redraw on @self limited to a specific, actor-relative
7782  * rectangular area.
7783  *
7784  * If @clip is %NULL this function is equivalent to
7785  * clutter_actor_queue_redraw().
7786  *
7787  * Since: 1.10
7788  */
7789 void
7790 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7791                                       const cairo_rectangle_int_t *clip)
7792 {
7793   ClutterPaintVolume volume;
7794   ClutterVertex origin;
7795
7796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7797
7798   if (clip == NULL)
7799     {
7800       clutter_actor_queue_redraw (self);
7801       return;
7802     }
7803
7804   _clutter_paint_volume_init_static (&volume, self);
7805
7806   origin.x = clip->x;
7807   origin.y = clip->y;
7808   origin.z = 0.0f;
7809
7810   clutter_paint_volume_set_origin (&volume, &origin);
7811   clutter_paint_volume_set_width (&volume, clip->width);
7812   clutter_paint_volume_set_height (&volume, clip->height);
7813
7814   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7815
7816   clutter_paint_volume_free (&volume);
7817 }
7818
7819 /**
7820  * clutter_actor_queue_relayout:
7821  * @self: A #ClutterActor
7822  *
7823  * Indicates that the actor's size request or other layout-affecting
7824  * properties may have changed. This function is used inside #ClutterActor
7825  * subclass implementations, not by applications directly.
7826  *
7827  * Queueing a new layout automatically queues a redraw as well.
7828  *
7829  * Since: 0.8
7830  */
7831 void
7832 clutter_actor_queue_relayout (ClutterActor *self)
7833 {
7834   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7835
7836   _clutter_actor_queue_only_relayout (self);
7837   clutter_actor_queue_redraw (self);
7838 }
7839
7840 /**
7841  * clutter_actor_get_preferred_size:
7842  * @self: a #ClutterActor
7843  * @min_width_p: (out) (allow-none): return location for the minimum
7844  *   width, or %NULL
7845  * @min_height_p: (out) (allow-none): return location for the minimum
7846  *   height, or %NULL
7847  * @natural_width_p: (out) (allow-none): return location for the natural
7848  *   width, or %NULL
7849  * @natural_height_p: (out) (allow-none): return location for the natural
7850  *   height, or %NULL
7851  *
7852  * Computes the preferred minimum and natural size of an actor, taking into
7853  * account the actor's geometry management (either height-for-width
7854  * or width-for-height).
7855  *
7856  * The width and height used to compute the preferred height and preferred
7857  * width are the actor's natural ones.
7858  *
7859  * If you need to control the height for the preferred width, or the width for
7860  * the preferred height, you should use clutter_actor_get_preferred_width()
7861  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7862  * geometry management using the #ClutterActor:request-mode property.
7863  *
7864  * Since: 0.8
7865  */
7866 void
7867 clutter_actor_get_preferred_size (ClutterActor *self,
7868                                   gfloat       *min_width_p,
7869                                   gfloat       *min_height_p,
7870                                   gfloat       *natural_width_p,
7871                                   gfloat       *natural_height_p)
7872 {
7873   ClutterActorPrivate *priv;
7874   gfloat min_width, min_height;
7875   gfloat natural_width, natural_height;
7876
7877   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7878
7879   priv = self->priv;
7880
7881   min_width = min_height = 0;
7882   natural_width = natural_height = 0;
7883
7884   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7885     {
7886       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7887       clutter_actor_get_preferred_width (self, -1,
7888                                          &min_width,
7889                                          &natural_width);
7890       clutter_actor_get_preferred_height (self, natural_width,
7891                                           &min_height,
7892                                           &natural_height);
7893     }
7894   else
7895     {
7896       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7897       clutter_actor_get_preferred_height (self, -1,
7898                                           &min_height,
7899                                           &natural_height);
7900       clutter_actor_get_preferred_width (self, natural_height,
7901                                          &min_width,
7902                                          &natural_width);
7903     }
7904
7905   if (min_width_p)
7906     *min_width_p = min_width;
7907
7908   if (min_height_p)
7909     *min_height_p = min_height;
7910
7911   if (natural_width_p)
7912     *natural_width_p = natural_width;
7913
7914   if (natural_height_p)
7915     *natural_height_p = natural_height;
7916 }
7917
7918 /*< private >
7919  * effective_align:
7920  * @align: a #ClutterActorAlign
7921  * @direction: a #ClutterTextDirection
7922  *
7923  * Retrieves the correct alignment depending on the text direction
7924  *
7925  * Return value: the effective alignment
7926  */
7927 static ClutterActorAlign
7928 effective_align (ClutterActorAlign    align,
7929                  ClutterTextDirection direction)
7930 {
7931   ClutterActorAlign res;
7932
7933   switch (align)
7934     {
7935     case CLUTTER_ACTOR_ALIGN_START:
7936       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7937           ? CLUTTER_ACTOR_ALIGN_END
7938           : CLUTTER_ACTOR_ALIGN_START;
7939       break;
7940
7941     case CLUTTER_ACTOR_ALIGN_END:
7942       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7943           ? CLUTTER_ACTOR_ALIGN_START
7944           : CLUTTER_ACTOR_ALIGN_END;
7945       break;
7946
7947     default:
7948       res = align;
7949       break;
7950     }
7951
7952   return res;
7953 }
7954
7955 static inline void
7956 adjust_for_margin (float  margin_start,
7957                    float  margin_end,
7958                    float *minimum_size,
7959                    float *natural_size,
7960                    float *allocated_start,
7961                    float *allocated_end)
7962 {
7963   *minimum_size -= (margin_start + margin_end);
7964   *natural_size -= (margin_start + margin_end);
7965   *allocated_start += margin_start;
7966   *allocated_end -= margin_end;
7967 }
7968
7969 static inline void
7970 adjust_for_alignment (ClutterActorAlign  alignment,
7971                       float              natural_size,
7972                       float             *allocated_start,
7973                       float             *allocated_end)
7974 {
7975   float allocated_size = *allocated_end - *allocated_start;
7976
7977   switch (alignment)
7978     {
7979     case CLUTTER_ACTOR_ALIGN_FILL:
7980       /* do nothing */
7981       break;
7982
7983     case CLUTTER_ACTOR_ALIGN_START:
7984       /* keep start */
7985       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7986       break;
7987
7988     case CLUTTER_ACTOR_ALIGN_END:
7989       if (allocated_size > natural_size)
7990         {
7991           *allocated_start += (allocated_size - natural_size);
7992           *allocated_end = *allocated_start + natural_size;
7993         }
7994       break;
7995
7996     case CLUTTER_ACTOR_ALIGN_CENTER:
7997       if (allocated_size > natural_size)
7998         {
7999           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8000           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8001         }
8002       break;
8003     }
8004 }
8005
8006 /*< private >
8007  * clutter_actor_adjust_width:
8008  * @self: a #ClutterActor
8009  * @minimum_width: (inout): the actor's preferred minimum width, which
8010  *   will be adjusted depending on the margin
8011  * @natural_width: (inout): the actor's preferred natural width, which
8012  *   will be adjusted depending on the margin
8013  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8014  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8015  *
8016  * Adjusts the preferred and allocated position and size of an actor,
8017  * depending on the margin and alignment properties.
8018  */
8019 static void
8020 clutter_actor_adjust_width (ClutterActor *self,
8021                             gfloat       *minimum_width,
8022                             gfloat       *natural_width,
8023                             gfloat       *adjusted_x1,
8024                             gfloat       *adjusted_x2)
8025 {
8026   ClutterTextDirection text_dir;
8027   const ClutterLayoutInfo *info;
8028
8029   info = _clutter_actor_get_layout_info_or_defaults (self);
8030   text_dir = clutter_actor_get_text_direction (self);
8031
8032   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8033
8034   /* this will tweak natural_width to remove the margin, so that
8035    * adjust_for_alignment() will use the correct size
8036    */
8037   adjust_for_margin (info->margin.left, info->margin.right,
8038                      minimum_width, natural_width,
8039                      adjusted_x1, adjusted_x2);
8040
8041   adjust_for_alignment (effective_align (info->x_align, text_dir),
8042                         *natural_width,
8043                         adjusted_x1, adjusted_x2);
8044 }
8045
8046 /*< private >
8047  * clutter_actor_adjust_height:
8048  * @self: a #ClutterActor
8049  * @minimum_height: (inout): the actor's preferred minimum height, which
8050  *   will be adjusted depending on the margin
8051  * @natural_height: (inout): the actor's preferred natural height, which
8052  *   will be adjusted depending on the margin
8053  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8054  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8055  *
8056  * Adjusts the preferred and allocated position and size of an actor,
8057  * depending on the margin and alignment properties.
8058  */
8059 static void
8060 clutter_actor_adjust_height (ClutterActor *self,
8061                              gfloat       *minimum_height,
8062                              gfloat       *natural_height,
8063                              gfloat       *adjusted_y1,
8064                              gfloat       *adjusted_y2)
8065 {
8066   const ClutterLayoutInfo *info;
8067
8068   info = _clutter_actor_get_layout_info_or_defaults (self);
8069
8070   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8071
8072   /* this will tweak natural_height to remove the margin, so that
8073    * adjust_for_alignment() will use the correct size
8074    */
8075   adjust_for_margin (info->margin.top, info->margin.bottom,
8076                      minimum_height, natural_height,
8077                      adjusted_y1,
8078                      adjusted_y2);
8079
8080   /* we don't use effective_align() here, because text direction
8081    * only affects the horizontal axis
8082    */
8083   adjust_for_alignment (info->y_align,
8084                         *natural_height,
8085                         adjusted_y1,
8086                         adjusted_y2);
8087
8088 }
8089
8090 /* looks for a cached size request for this for_size. If not
8091  * found, returns the oldest entry so it can be overwritten */
8092 static gboolean
8093 _clutter_actor_get_cached_size_request (gfloat         for_size,
8094                                         SizeRequest   *cached_size_requests,
8095                                         SizeRequest  **result)
8096 {
8097   guint i;
8098
8099   *result = &cached_size_requests[0];
8100
8101   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8102     {
8103       SizeRequest *sr;
8104
8105       sr = &cached_size_requests[i];
8106
8107       if (sr->age > 0 &&
8108           sr->for_size == for_size)
8109         {
8110           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8111           *result = sr;
8112           return TRUE;
8113         }
8114       else if (sr->age < (*result)->age)
8115         {
8116           *result = sr;
8117         }
8118     }
8119
8120   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8121
8122   return FALSE;
8123 }
8124
8125 /**
8126  * clutter_actor_get_preferred_width:
8127  * @self: A #ClutterActor
8128  * @for_height: available height when computing the preferred width,
8129  *   or a negative value to indicate that no height is defined
8130  * @min_width_p: (out) (allow-none): return location for minimum width,
8131  *   or %NULL
8132  * @natural_width_p: (out) (allow-none): return location for the natural
8133  *   width, or %NULL
8134  *
8135  * Computes the requested minimum and natural widths for an actor,
8136  * optionally depending on the specified height, or if they are
8137  * already computed, returns the cached values.
8138  *
8139  * An actor may not get its request - depending on the layout
8140  * manager that's in effect.
8141  *
8142  * A request should not incorporate the actor's scale or anchor point;
8143  * those transformations do not affect layout, only rendering.
8144  *
8145  * Since: 0.8
8146  */
8147 void
8148 clutter_actor_get_preferred_width (ClutterActor *self,
8149                                    gfloat        for_height,
8150                                    gfloat       *min_width_p,
8151                                    gfloat       *natural_width_p)
8152 {
8153   float request_min_width, request_natural_width;
8154   SizeRequest *cached_size_request;
8155   const ClutterLayoutInfo *info;
8156   ClutterActorPrivate *priv;
8157   gboolean found_in_cache;
8158
8159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8160
8161   priv = self->priv;
8162
8163   info = _clutter_actor_get_layout_info_or_defaults (self);
8164
8165   /* we shortcircuit the case of a fixed size set using set_width() */
8166   if (priv->min_width_set && priv->natural_width_set)
8167     {
8168       if (min_width_p != NULL)
8169         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8170
8171       if (natural_width_p != NULL)
8172         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8173
8174       return;
8175     }
8176
8177   /* the remaining cases are:
8178    *
8179    *   - either min_width or natural_width have been set
8180    *   - neither min_width or natural_width have been set
8181    *
8182    * in both cases, we go through the cache (and through the actor in case
8183    * of cache misses) and determine the authoritative value depending on
8184    * the *_set flags.
8185    */
8186
8187   if (!priv->needs_width_request)
8188     {
8189       found_in_cache =
8190         _clutter_actor_get_cached_size_request (for_height,
8191                                                 priv->width_requests,
8192                                                 &cached_size_request);
8193     }
8194   else
8195     {
8196       /* if the actor needs a width request we use the first slot */
8197       found_in_cache = FALSE;
8198       cached_size_request = &priv->width_requests[0];
8199     }
8200
8201   if (!found_in_cache)
8202     {
8203       gfloat minimum_width, natural_width;
8204       ClutterActorClass *klass;
8205
8206       minimum_width = natural_width = 0;
8207
8208       /* adjust for the margin */
8209       if (for_height >= 0)
8210         {
8211           for_height -= (info->margin.top + info->margin.bottom);
8212           if (for_height < 0)
8213             for_height = 0;
8214         }
8215
8216       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8217
8218       klass = CLUTTER_ACTOR_GET_CLASS (self);
8219       klass->get_preferred_width (self, for_height,
8220                                   &minimum_width,
8221                                   &natural_width);
8222
8223       /* adjust for the margin */
8224       minimum_width += (info->margin.left + info->margin.right);
8225       natural_width += (info->margin.left + info->margin.right);
8226
8227       /* Due to accumulated float errors, it's better not to warn
8228        * on this, but just fix it.
8229        */
8230       if (natural_width < minimum_width)
8231         natural_width = minimum_width;
8232
8233       cached_size_request->min_size = minimum_width;
8234       cached_size_request->natural_size = natural_width;
8235       cached_size_request->for_size = for_height;
8236       cached_size_request->age = priv->cached_width_age;
8237
8238       priv->cached_width_age += 1;
8239       priv->needs_width_request = FALSE;
8240     }
8241
8242   if (!priv->min_width_set)
8243     request_min_width = cached_size_request->min_size;
8244   else
8245     request_min_width = info->minimum.width;
8246
8247   if (!priv->natural_width_set)
8248     request_natural_width = cached_size_request->natural_size;
8249   else
8250     request_natural_width = info->natural.width;
8251
8252   if (min_width_p)
8253     *min_width_p = request_min_width;
8254
8255   if (natural_width_p)
8256     *natural_width_p = request_natural_width;
8257 }
8258
8259 /**
8260  * clutter_actor_get_preferred_height:
8261  * @self: A #ClutterActor
8262  * @for_width: available width to assume in computing desired height,
8263  *   or a negative value to indicate that no width is defined
8264  * @min_height_p: (out) (allow-none): return location for minimum height,
8265  *   or %NULL
8266  * @natural_height_p: (out) (allow-none): return location for natural
8267  *   height, or %NULL
8268  *
8269  * Computes the requested minimum and natural heights for an actor,
8270  * or if they are already computed, returns the cached values.
8271  *
8272  * An actor may not get its request - depending on the layout
8273  * manager that's in effect.
8274  *
8275  * A request should not incorporate the actor's scale or anchor point;
8276  * those transformations do not affect layout, only rendering.
8277  *
8278  * Since: 0.8
8279  */
8280 void
8281 clutter_actor_get_preferred_height (ClutterActor *self,
8282                                     gfloat        for_width,
8283                                     gfloat       *min_height_p,
8284                                     gfloat       *natural_height_p)
8285 {
8286   float request_min_height, request_natural_height;
8287   SizeRequest *cached_size_request;
8288   const ClutterLayoutInfo *info;
8289   ClutterActorPrivate *priv;
8290   gboolean found_in_cache;
8291
8292   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8293
8294   priv = self->priv;
8295
8296   info = _clutter_actor_get_layout_info_or_defaults (self);
8297
8298   /* we shortcircuit the case of a fixed size set using set_height() */
8299   if (priv->min_height_set && priv->natural_height_set)
8300     {
8301       if (min_height_p != NULL)
8302         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8303
8304       if (natural_height_p != NULL)
8305         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8306
8307       return;
8308     }
8309
8310   /* the remaining cases are:
8311    *
8312    *   - either min_height or natural_height have been set
8313    *   - neither min_height or natural_height have been set
8314    *
8315    * in both cases, we go through the cache (and through the actor in case
8316    * of cache misses) and determine the authoritative value depending on
8317    * the *_set flags.
8318    */
8319
8320   if (!priv->needs_height_request)
8321     {
8322       found_in_cache =
8323         _clutter_actor_get_cached_size_request (for_width,
8324                                                 priv->height_requests,
8325                                                 &cached_size_request);
8326     }
8327   else
8328     {
8329       found_in_cache = FALSE;
8330       cached_size_request = &priv->height_requests[0];
8331     }
8332
8333   if (!found_in_cache)
8334     {
8335       gfloat minimum_height, natural_height;
8336       ClutterActorClass *klass;
8337
8338       minimum_height = natural_height = 0;
8339
8340       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8341
8342       /* adjust for margin */
8343       if (for_width >= 0)
8344         {
8345           for_width -= (info->margin.left + info->margin.right);
8346           if (for_width < 0)
8347             for_width = 0;
8348         }
8349
8350       klass = CLUTTER_ACTOR_GET_CLASS (self);
8351       klass->get_preferred_height (self, for_width,
8352                                    &minimum_height,
8353                                    &natural_height);
8354
8355       /* adjust for margin */
8356       minimum_height += (info->margin.top + info->margin.bottom);
8357       natural_height += (info->margin.top + info->margin.bottom);
8358
8359       /* Due to accumulated float errors, it's better not to warn
8360        * on this, but just fix it.
8361        */
8362       if (natural_height < minimum_height)
8363         natural_height = minimum_height;
8364
8365       cached_size_request->min_size = minimum_height;
8366       cached_size_request->natural_size = natural_height;
8367       cached_size_request->for_size = for_width;
8368       cached_size_request->age = priv->cached_height_age;
8369
8370       priv->cached_height_age += 1;
8371       priv->needs_height_request = FALSE;
8372     }
8373
8374   if (!priv->min_height_set)
8375     request_min_height = cached_size_request->min_size;
8376   else
8377     request_min_height = info->minimum.height;
8378
8379   if (!priv->natural_height_set)
8380     request_natural_height = cached_size_request->natural_size;
8381   else
8382     request_natural_height = info->natural.height;
8383
8384   if (min_height_p)
8385     *min_height_p = request_min_height;
8386
8387   if (natural_height_p)
8388     *natural_height_p = request_natural_height;
8389 }
8390
8391 /**
8392  * clutter_actor_get_allocation_box:
8393  * @self: A #ClutterActor
8394  * @box: (out): the function fills this in with the actor's allocation
8395  *
8396  * Gets the layout box an actor has been assigned. The allocation can
8397  * only be assumed valid inside a paint() method; anywhere else, it
8398  * may be out-of-date.
8399  *
8400  * An allocation does not incorporate the actor's scale or anchor point;
8401  * those transformations do not affect layout, only rendering.
8402  *
8403  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8404  * of functions inside the implementation of the get_preferred_width()
8405  * or get_preferred_height() virtual functions.</note>
8406  *
8407  * Since: 0.8
8408  */
8409 void
8410 clutter_actor_get_allocation_box (ClutterActor    *self,
8411                                   ClutterActorBox *box)
8412 {
8413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8414
8415   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8416    * which limits calling get_allocation to inside paint() basically; or
8417    * we can 2) force a layout, which could be expensive if someone calls
8418    * get_allocation somewhere silly; or we can 3) just return the latest
8419    * value, allowing it to be out-of-date, and assume people know what
8420    * they are doing.
8421    *
8422    * The least-surprises approach that keeps existing code working is
8423    * likely to be 2). People can end up doing some inefficient things,
8424    * though, and in general code that requires 2) is probably broken.
8425    */
8426
8427   /* this implements 2) */
8428   if (G_UNLIKELY (self->priv->needs_allocation))
8429     {
8430       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8431
8432       /* do not queue a relayout on an unparented actor */
8433       if (stage)
8434         _clutter_stage_maybe_relayout (stage);
8435     }
8436
8437   /* commenting out the code above and just keeping this assigment
8438    * implements 3)
8439    */
8440   *box = self->priv->allocation;
8441 }
8442
8443 /**
8444  * clutter_actor_get_allocation_geometry:
8445  * @self: A #ClutterActor
8446  * @geom: (out): allocation geometry in pixels
8447  *
8448  * Gets the layout box an actor has been assigned.  The allocation can
8449  * only be assumed valid inside a paint() method; anywhere else, it
8450  * may be out-of-date.
8451  *
8452  * An allocation does not incorporate the actor's scale or anchor point;
8453  * those transformations do not affect layout, only rendering.
8454  *
8455  * The returned rectangle is in pixels.
8456  *
8457  * Since: 0.8
8458  */
8459 void
8460 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8461                                        ClutterGeometry *geom)
8462 {
8463   ClutterActorBox box;
8464
8465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8466   g_return_if_fail (geom != NULL);
8467
8468   clutter_actor_get_allocation_box (self, &box);
8469
8470   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8471   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8472   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8473   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8474 }
8475
8476 static void
8477 clutter_actor_update_constraints (ClutterActor    *self,
8478                                   ClutterActorBox *allocation)
8479 {
8480   ClutterActorPrivate *priv = self->priv;
8481   const GList *constraints, *l;
8482
8483   if (priv->constraints == NULL)
8484     return;
8485
8486   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8487   for (l = constraints; l != NULL; l = l->next)
8488     {
8489       ClutterConstraint *constraint = l->data;
8490       ClutterActorMeta *meta = l->data;
8491
8492       if (clutter_actor_meta_get_enabled (meta))
8493         {
8494           _clutter_constraint_update_allocation (constraint,
8495                                                  self,
8496                                                  allocation);
8497
8498           CLUTTER_NOTE (LAYOUT,
8499                         "Allocation of '%s' after constraint '%s': "
8500                         "{ %.2f, %.2f, %.2f, %.2f }",
8501                         _clutter_actor_get_debug_name (self),
8502                         _clutter_actor_meta_get_debug_name (meta),
8503                         allocation->x1,
8504                         allocation->y1,
8505                         allocation->x2,
8506                         allocation->y2);
8507         }
8508     }
8509 }
8510
8511 /*< private >
8512  * clutter_actor_adjust_allocation:
8513  * @self: a #ClutterActor
8514  * @allocation: (inout): the allocation to adjust
8515  *
8516  * Adjusts the passed allocation box taking into account the actor's
8517  * layout information, like alignment, expansion, and margin.
8518  */
8519 static void
8520 clutter_actor_adjust_allocation (ClutterActor    *self,
8521                                  ClutterActorBox *allocation)
8522 {
8523   ClutterActorBox adj_allocation;
8524   float alloc_width, alloc_height;
8525   float min_width, min_height;
8526   float nat_width, nat_height;
8527   ClutterRequestMode req_mode;
8528
8529   adj_allocation = *allocation;
8530
8531   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8532
8533   /* we want to hit the cache, so we use the public API */
8534   req_mode = clutter_actor_get_request_mode (self);
8535
8536   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8537     {
8538       clutter_actor_get_preferred_width (self, -1,
8539                                          &min_width,
8540                                          &nat_width);
8541       clutter_actor_get_preferred_height (self, alloc_width,
8542                                           &min_height,
8543                                           &nat_height);
8544     }
8545   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8546     {
8547       clutter_actor_get_preferred_height (self, -1,
8548                                           &min_height,
8549                                           &nat_height);
8550       clutter_actor_get_preferred_height (self, alloc_height,
8551                                           &min_width,
8552                                           &nat_width);
8553     }
8554
8555 #ifdef CLUTTER_ENABLE_DEBUG
8556   /* warn about underallocations */
8557   if (_clutter_diagnostic_enabled () &&
8558       (floorf (min_width - alloc_width) > 0 ||
8559        floorf (min_height - alloc_height) > 0))
8560     {
8561       ClutterActor *parent = clutter_actor_get_parent (self);
8562
8563       /* the only actors that are allowed to be underallocated are the Stage,
8564        * as it doesn't have an implicit size, and Actors that specifically
8565        * told us that they want to opt-out from layout control mechanisms
8566        * through the NO_LAYOUT escape hatch.
8567        */
8568       if (parent != NULL &&
8569           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8570         {
8571           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8572                      "of %.2f x %.2f from its parent actor '%s', but its "
8573                      "requested minimum size is of %.2f x %.2f",
8574                      _clutter_actor_get_debug_name (self),
8575                      alloc_width, alloc_height,
8576                      _clutter_actor_get_debug_name (parent),
8577                      min_width, min_height);
8578         }
8579     }
8580 #endif
8581
8582   clutter_actor_adjust_width (self,
8583                               &min_width,
8584                               &nat_width,
8585                               &adj_allocation.x1,
8586                               &adj_allocation.x2);
8587
8588   clutter_actor_adjust_height (self,
8589                                &min_height,
8590                                &nat_height,
8591                                &adj_allocation.y1,
8592                                &adj_allocation.y2);
8593
8594   /* we maintain the invariant that an allocation cannot be adjusted
8595    * to be outside the parent-given box
8596    */
8597   if (adj_allocation.x1 < allocation->x1 ||
8598       adj_allocation.y1 < allocation->y1 ||
8599       adj_allocation.x2 > allocation->x2 ||
8600       adj_allocation.y2 > allocation->y2)
8601     {
8602       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8603                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8604                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8605                  _clutter_actor_get_debug_name (self),
8606                  adj_allocation.x1, adj_allocation.y1,
8607                  adj_allocation.x2 - adj_allocation.x1,
8608                  adj_allocation.y2 - adj_allocation.y1,
8609                  allocation->x1, allocation->y1,
8610                  allocation->x2 - allocation->x1,
8611                  allocation->y2 - allocation->y1);
8612       return;
8613     }
8614
8615   *allocation = adj_allocation;
8616 }
8617
8618 /**
8619  * clutter_actor_allocate:
8620  * @self: A #ClutterActor
8621  * @box: new allocation of the actor, in parent-relative coordinates
8622  * @flags: flags that control the allocation
8623  *
8624  * Called by the parent of an actor to assign the actor its size.
8625  * Should never be called by applications (except when implementing
8626  * a container or layout manager).
8627  *
8628  * Actors can know from their allocation box whether they have moved
8629  * with respect to their parent actor. The @flags parameter describes
8630  * additional information about the allocation, for instance whether
8631  * the parent has moved with respect to the stage, for example because
8632  * a grandparent's origin has moved.
8633  *
8634  * Since: 0.8
8635  */
8636 void
8637 clutter_actor_allocate (ClutterActor           *self,
8638                         const ClutterActorBox  *box,
8639                         ClutterAllocationFlags  flags)
8640 {
8641   ClutterActorPrivate *priv;
8642   ClutterActorClass *klass;
8643   ClutterActorBox old_allocation, real_allocation;
8644   gboolean origin_changed, child_moved, size_changed;
8645   gboolean stage_allocation_changed;
8646
8647   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8648   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8649     {
8650       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8651                  "which isn't a descendent of the stage!\n",
8652                  self, _clutter_actor_get_debug_name (self));
8653       return;
8654     }
8655
8656   priv = self->priv;
8657
8658   old_allocation = priv->allocation;
8659   real_allocation = *box;
8660
8661   /* constraints are allowed to modify the allocation only here; we do
8662    * this prior to all the other checks so that we can bail out if the
8663    * allocation did not change
8664    */
8665   clutter_actor_update_constraints (self, &real_allocation);
8666
8667   /* adjust the allocation depending on the align/margin properties */
8668   clutter_actor_adjust_allocation (self, &real_allocation);
8669
8670   if (real_allocation.x2 < real_allocation.x1 ||
8671       real_allocation.y2 < real_allocation.y1)
8672     {
8673       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8674                  _clutter_actor_get_debug_name (self),
8675                  real_allocation.x2 - real_allocation.x1,
8676                  real_allocation.y2 - real_allocation.y1);
8677     }
8678
8679   /* we allow 0-sized actors, but not negative-sized ones */
8680   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8681   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8682
8683   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8684
8685   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8686                  real_allocation.y1 != old_allocation.y1);
8687
8688   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8689                   real_allocation.y2 != old_allocation.y2);
8690
8691   if (origin_changed || child_moved || size_changed)
8692     stage_allocation_changed = TRUE;
8693   else
8694     stage_allocation_changed = FALSE;
8695
8696   /* If we get an allocation "out of the blue"
8697    * (we did not queue relayout), then we want to
8698    * ignore it. But if we have needs_allocation set,
8699    * we want to guarantee that allocate() virtual
8700    * method is always called, i.e. that queue_relayout()
8701    * always results in an allocate() invocation on
8702    * an actor.
8703    *
8704    * The optimization here is to avoid re-allocating
8705    * actors that did not queue relayout and were
8706    * not moved.
8707    */
8708   if (!priv->needs_allocation && !stage_allocation_changed)
8709     {
8710       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8711       return;
8712     }
8713
8714   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8715    * clutter_actor_allocate(), it indicates whether the parent has its
8716    * absolute origin moved; when passed in to ClutterActor::allocate()
8717    * virtual method though, it indicates whether the child has its
8718    * absolute origin moved.  So we set it when child_moved is TRUE
8719    */
8720   if (child_moved)
8721     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8722
8723   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8724
8725   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8726                 _clutter_actor_get_debug_name (self));
8727
8728   klass = CLUTTER_ACTOR_GET_CLASS (self);
8729   klass->allocate (self, &real_allocation, flags);
8730
8731   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8732
8733   if (stage_allocation_changed)
8734     clutter_actor_queue_redraw (self);
8735 }
8736
8737 /**
8738  * clutter_actor_set_allocation:
8739  * @self: a #ClutterActor
8740  * @box: a #ClutterActorBox
8741  * @flags: allocation flags
8742  *
8743  * Stores the allocation of @self as defined by @box.
8744  *
8745  * This function can only be called from within the implementation of
8746  * the #ClutterActorClass.allocate() virtual function.
8747  *
8748  * The allocation should have been adjusted to take into account constraints,
8749  * alignment, and margin properties. If you are implementing a #ClutterActor
8750  * subclass that provides its own layout management policy for its children
8751  * instead of using a #ClutterLayoutManager delegate, you should not call
8752  * this function on the children of @self; instead, you should call
8753  * clutter_actor_allocate(), which will adjust the allocation box for
8754  * you.
8755  *
8756  * This function should only be used by subclasses of #ClutterActor
8757  * that wish to store their allocation but cannot chain up to the
8758  * parent's implementation; the default implementation of the
8759  * #ClutterActorClass.allocate() virtual function will call this
8760  * function.
8761  *
8762  * It is important to note that, while chaining up was the recommended
8763  * behaviour for #ClutterActor subclasses prior to the introduction of
8764  * this function, it is recommended to call clutter_actor_set_allocation()
8765  * instead.
8766  *
8767  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8768  * to handle the allocation of its children, this function will call
8769  * the clutter_layout_manager_allocate() function only if the
8770  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8771  * expected that the subclass will call clutter_layout_manager_allocate()
8772  * by itself. For instance, the following code:
8773  *
8774  * |[
8775  * static void
8776  * my_actor_allocate (ClutterActor *actor,
8777  *                    const ClutterActorBox *allocation,
8778  *                    ClutterAllocationFlags flags)
8779  * {
8780  *   ClutterActorBox new_alloc;
8781  *   ClutterAllocationFlags new_flags;
8782  *
8783  *   adjust_allocation (allocation, &amp;new_alloc);
8784  *
8785  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8786  *
8787  *   /&ast; this will use the layout manager set on the actor &ast;/
8788  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8789  * }
8790  * ]|
8791  *
8792  * is equivalent to this:
8793  *
8794  * |[
8795  * static void
8796  * my_actor_allocate (ClutterActor *actor,
8797  *                    const ClutterActorBox *allocation,
8798  *                    ClutterAllocationFlags flags)
8799  * {
8800  *   ClutterLayoutManager *layout;
8801  *   ClutterActorBox new_alloc;
8802  *
8803  *   adjust_allocation (allocation, &amp;new_alloc);
8804  *
8805  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8806  *
8807  *   layout = clutter_actor_get_layout_manager (actor);
8808  *   clutter_layout_manager_allocate (layout,
8809  *                                    CLUTTER_CONTAINER (actor),
8810  *                                    &amp;new_alloc,
8811  *                                    flags);
8812  * }
8813  * ]|
8814  *
8815  * Since: 1.10
8816  */
8817 void
8818 clutter_actor_set_allocation (ClutterActor           *self,
8819                               const ClutterActorBox  *box,
8820                               ClutterAllocationFlags  flags)
8821 {
8822   ClutterActorPrivate *priv;
8823   gboolean changed;
8824
8825   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8826   g_return_if_fail (box != NULL);
8827
8828   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8829     {
8830       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8831                   "can only be called from within the implementation of "
8832                   "the ClutterActor::allocate() virtual function.");
8833       return;
8834     }
8835
8836   priv = self->priv;
8837
8838   g_object_freeze_notify (G_OBJECT (self));
8839
8840   changed = clutter_actor_set_allocation_internal (self, box, flags);
8841
8842   /* we allocate our children before we notify changes in our geometry,
8843    * so that people connecting to properties will be able to get valid
8844    * data out of the sub-tree of the scene graph that has this actor at
8845    * the root.
8846    */
8847   clutter_actor_maybe_layout_children (self, box, flags);
8848
8849   if (changed)
8850     {
8851       ClutterActorBox signal_box = priv->allocation;
8852       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8853
8854       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8855                      &signal_box,
8856                      signal_flags);
8857     }
8858
8859   g_object_thaw_notify (G_OBJECT (self));
8860 }
8861
8862 /**
8863  * clutter_actor_set_geometry:
8864  * @self: A #ClutterActor
8865  * @geometry: A #ClutterGeometry
8866  *
8867  * Sets the actor's fixed position and forces its minimum and natural
8868  * size, in pixels. This means the untransformed actor will have the
8869  * given geometry. This is the same as calling clutter_actor_set_position()
8870  * and clutter_actor_set_size().
8871  *
8872  * Deprecated: 1.10: Use clutter_actor_set_position() and
8873  *   clutter_actor_set_size() instead.
8874  */
8875 void
8876 clutter_actor_set_geometry (ClutterActor          *self,
8877                             const ClutterGeometry *geometry)
8878 {
8879   g_object_freeze_notify (G_OBJECT (self));
8880
8881   clutter_actor_set_position (self, geometry->x, geometry->y);
8882   clutter_actor_set_size (self, geometry->width, geometry->height);
8883
8884   g_object_thaw_notify (G_OBJECT (self));
8885 }
8886
8887 /**
8888  * clutter_actor_get_geometry:
8889  * @self: A #ClutterActor
8890  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8891  *
8892  * Gets the size and position of an actor relative to its parent
8893  * actor. This is the same as calling clutter_actor_get_position() and
8894  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8895  * requested size and position if the actor's allocation is invalid.
8896  *
8897  * Deprecated: 1.10: Use clutter_actor_get_position() and
8898  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8899  *   instead.
8900  */
8901 void
8902 clutter_actor_get_geometry (ClutterActor    *self,
8903                             ClutterGeometry *geometry)
8904 {
8905   gfloat x, y, width, height;
8906
8907   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8908   g_return_if_fail (geometry != NULL);
8909
8910   clutter_actor_get_position (self, &x, &y);
8911   clutter_actor_get_size (self, &width, &height);
8912
8913   geometry->x = (int) x;
8914   geometry->y = (int) y;
8915   geometry->width = (int) width;
8916   geometry->height = (int) height;
8917 }
8918
8919 /**
8920  * clutter_actor_set_position:
8921  * @self: A #ClutterActor
8922  * @x: New left position of actor in pixels.
8923  * @y: New top position of actor in pixels.
8924  *
8925  * Sets the actor's fixed position in pixels relative to any parent
8926  * actor.
8927  *
8928  * If a layout manager is in use, this position will override the
8929  * layout manager and force a fixed position.
8930  */
8931 void
8932 clutter_actor_set_position (ClutterActor *self,
8933                             gfloat        x,
8934                             gfloat        y)
8935 {
8936   ClutterPoint new_position;
8937
8938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8939
8940   clutter_point_init (&new_position, x, y);
8941
8942   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8943     {
8944       ClutterPoint cur_position;
8945
8946       cur_position.x = clutter_actor_get_x (self);
8947       cur_position.y = clutter_actor_get_y (self);
8948
8949       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8950                                         &cur_position,
8951                                         &new_position);
8952     }
8953   else
8954     _clutter_actor_update_transition (self,
8955                                       obj_props[PROP_POSITION],
8956                                       &new_position);
8957
8958   clutter_actor_queue_relayout (self);
8959 }
8960
8961 /**
8962  * clutter_actor_get_fixed_position_set:
8963  * @self: A #ClutterActor
8964  *
8965  * Checks whether an actor has a fixed position set (and will thus be
8966  * unaffected by any layout manager).
8967  *
8968  * Return value: %TRUE if the fixed position is set on the actor
8969  *
8970  * Since: 0.8
8971  */
8972 gboolean
8973 clutter_actor_get_fixed_position_set (ClutterActor *self)
8974 {
8975   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8976
8977   return self->priv->position_set;
8978 }
8979
8980 /**
8981  * clutter_actor_set_fixed_position_set:
8982  * @self: A #ClutterActor
8983  * @is_set: whether to use fixed position
8984  *
8985  * Sets whether an actor has a fixed position set (and will thus be
8986  * unaffected by any layout manager).
8987  *
8988  * Since: 0.8
8989  */
8990 void
8991 clutter_actor_set_fixed_position_set (ClutterActor *self,
8992                                       gboolean      is_set)
8993 {
8994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8995
8996   if (self->priv->position_set == (is_set != FALSE))
8997     return;
8998
8999   self->priv->position_set = is_set != FALSE;
9000   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9001
9002   clutter_actor_queue_relayout (self);
9003 }
9004
9005 /**
9006  * clutter_actor_move_by:
9007  * @self: A #ClutterActor
9008  * @dx: Distance to move Actor on X axis.
9009  * @dy: Distance to move Actor on Y axis.
9010  *
9011  * Moves an actor by the specified distance relative to its current
9012  * position in pixels.
9013  *
9014  * This function modifies the fixed position of an actor and thus removes
9015  * it from any layout management. Another way to move an actor is with an
9016  * anchor point, see clutter_actor_set_anchor_point().
9017  *
9018  * Since: 0.2
9019  */
9020 void
9021 clutter_actor_move_by (ClutterActor *self,
9022                        gfloat        dx,
9023                        gfloat        dy)
9024 {
9025   const ClutterLayoutInfo *info;
9026   gfloat x, y;
9027
9028   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9029
9030   info = _clutter_actor_get_layout_info_or_defaults (self);
9031   x = info->fixed_pos.x;
9032   y = info->fixed_pos.y;
9033
9034   clutter_actor_set_position (self, x + dx, y + dy);
9035 }
9036
9037 static void
9038 clutter_actor_set_min_width (ClutterActor *self,
9039                              gfloat        min_width)
9040 {
9041   ClutterActorPrivate *priv = self->priv;
9042   ClutterActorBox old = { 0, };
9043   ClutterLayoutInfo *info;
9044
9045   /* if we are setting the size on a top-level actor and the
9046    * backend only supports static top-levels (e.g. framebuffers)
9047    * then we ignore the passed value and we override it with
9048    * the stage implementation's preferred size.
9049    */
9050   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9051       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9052     return;
9053
9054   info = _clutter_actor_get_layout_info (self);
9055
9056   if (priv->min_width_set && min_width == info->minimum.width)
9057     return;
9058
9059   g_object_freeze_notify (G_OBJECT (self));
9060
9061   clutter_actor_store_old_geometry (self, &old);
9062
9063   info->minimum.width = min_width;
9064   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9065   clutter_actor_set_min_width_set (self, TRUE);
9066
9067   clutter_actor_notify_if_geometry_changed (self, &old);
9068
9069   g_object_thaw_notify (G_OBJECT (self));
9070
9071   clutter_actor_queue_relayout (self);
9072 }
9073
9074 static void
9075 clutter_actor_set_min_height (ClutterActor *self,
9076                               gfloat        min_height)
9077
9078 {
9079   ClutterActorPrivate *priv = self->priv;
9080   ClutterActorBox old = { 0, };
9081   ClutterLayoutInfo *info;
9082
9083   /* if we are setting the size on a top-level actor and the
9084    * backend only supports static top-levels (e.g. framebuffers)
9085    * then we ignore the passed value and we override it with
9086    * the stage implementation's preferred size.
9087    */
9088   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9089       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9090     return;
9091
9092   info = _clutter_actor_get_layout_info (self);
9093
9094   if (priv->min_height_set && min_height == info->minimum.height)
9095     return;
9096
9097   g_object_freeze_notify (G_OBJECT (self));
9098
9099   clutter_actor_store_old_geometry (self, &old);
9100
9101   info->minimum.height = min_height;
9102   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9103   clutter_actor_set_min_height_set (self, TRUE);
9104
9105   clutter_actor_notify_if_geometry_changed (self, &old);
9106
9107   g_object_thaw_notify (G_OBJECT (self));
9108
9109   clutter_actor_queue_relayout (self);
9110 }
9111
9112 static void
9113 clutter_actor_set_natural_width (ClutterActor *self,
9114                                  gfloat        natural_width)
9115 {
9116   ClutterActorPrivate *priv = self->priv;
9117   ClutterActorBox old = { 0, };
9118   ClutterLayoutInfo *info;
9119
9120   /* if we are setting the size on a top-level actor and the
9121    * backend only supports static top-levels (e.g. framebuffers)
9122    * then we ignore the passed value and we override it with
9123    * the stage implementation's preferred size.
9124    */
9125   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9126       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9127     return;
9128
9129   info = _clutter_actor_get_layout_info (self);
9130
9131   if (priv->natural_width_set && natural_width == info->natural.width)
9132     return;
9133
9134   g_object_freeze_notify (G_OBJECT (self));
9135
9136   clutter_actor_store_old_geometry (self, &old);
9137
9138   info->natural.width = natural_width;
9139   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9140   clutter_actor_set_natural_width_set (self, TRUE);
9141
9142   clutter_actor_notify_if_geometry_changed (self, &old);
9143
9144   g_object_thaw_notify (G_OBJECT (self));
9145
9146   clutter_actor_queue_relayout (self);
9147 }
9148
9149 static void
9150 clutter_actor_set_natural_height (ClutterActor *self,
9151                                   gfloat        natural_height)
9152 {
9153   ClutterActorPrivate *priv = self->priv;
9154   ClutterActorBox old = { 0, };
9155   ClutterLayoutInfo *info;
9156
9157   /* if we are setting the size on a top-level actor and the
9158    * backend only supports static top-levels (e.g. framebuffers)
9159    * then we ignore the passed value and we override it with
9160    * the stage implementation's preferred size.
9161    */
9162   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9163       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9164     return;
9165
9166   info = _clutter_actor_get_layout_info (self);
9167
9168   if (priv->natural_height_set && natural_height == info->natural.height)
9169     return;
9170
9171   g_object_freeze_notify (G_OBJECT (self));
9172
9173   clutter_actor_store_old_geometry (self, &old);
9174
9175   info->natural.height = natural_height;
9176   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9177   clutter_actor_set_natural_height_set (self, TRUE);
9178
9179   clutter_actor_notify_if_geometry_changed (self, &old);
9180
9181   g_object_thaw_notify (G_OBJECT (self));
9182
9183   clutter_actor_queue_relayout (self);
9184 }
9185
9186 static void
9187 clutter_actor_set_min_width_set (ClutterActor *self,
9188                                  gboolean      use_min_width)
9189 {
9190   ClutterActorPrivate *priv = self->priv;
9191   ClutterActorBox old = { 0, };
9192
9193   if (priv->min_width_set == (use_min_width != FALSE))
9194     return;
9195
9196   clutter_actor_store_old_geometry (self, &old);
9197
9198   priv->min_width_set = use_min_width != FALSE;
9199   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9200
9201   clutter_actor_notify_if_geometry_changed (self, &old);
9202
9203   clutter_actor_queue_relayout (self);
9204 }
9205
9206 static void
9207 clutter_actor_set_min_height_set (ClutterActor *self,
9208                                   gboolean      use_min_height)
9209 {
9210   ClutterActorPrivate *priv = self->priv;
9211   ClutterActorBox old = { 0, };
9212
9213   if (priv->min_height_set == (use_min_height != FALSE))
9214     return;
9215
9216   clutter_actor_store_old_geometry (self, &old);
9217
9218   priv->min_height_set = use_min_height != FALSE;
9219   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9220
9221   clutter_actor_notify_if_geometry_changed (self, &old);
9222
9223   clutter_actor_queue_relayout (self);
9224 }
9225
9226 static void
9227 clutter_actor_set_natural_width_set (ClutterActor *self,
9228                                      gboolean      use_natural_width)
9229 {
9230   ClutterActorPrivate *priv = self->priv;
9231   ClutterActorBox old = { 0, };
9232
9233   if (priv->natural_width_set == (use_natural_width != FALSE))
9234     return;
9235
9236   clutter_actor_store_old_geometry (self, &old);
9237
9238   priv->natural_width_set = use_natural_width != FALSE;
9239   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9240
9241   clutter_actor_notify_if_geometry_changed (self, &old);
9242
9243   clutter_actor_queue_relayout (self);
9244 }
9245
9246 static void
9247 clutter_actor_set_natural_height_set (ClutterActor *self,
9248                                       gboolean      use_natural_height)
9249 {
9250   ClutterActorPrivate *priv = self->priv;
9251   ClutterActorBox old = { 0, };
9252
9253   if (priv->natural_height_set == (use_natural_height != FALSE))
9254     return;
9255
9256   clutter_actor_store_old_geometry (self, &old);
9257
9258   priv->natural_height_set = use_natural_height != FALSE;
9259   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9260
9261   clutter_actor_notify_if_geometry_changed (self, &old);
9262
9263   clutter_actor_queue_relayout (self);
9264 }
9265
9266 /**
9267  * clutter_actor_set_request_mode:
9268  * @self: a #ClutterActor
9269  * @mode: the request mode
9270  *
9271  * Sets the geometry request mode of @self.
9272  *
9273  * The @mode determines the order for invoking
9274  * clutter_actor_get_preferred_width() and
9275  * clutter_actor_get_preferred_height()
9276  *
9277  * Since: 1.2
9278  */
9279 void
9280 clutter_actor_set_request_mode (ClutterActor       *self,
9281                                 ClutterRequestMode  mode)
9282 {
9283   ClutterActorPrivate *priv;
9284
9285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9286
9287   priv = self->priv;
9288
9289   if (priv->request_mode == mode)
9290     return;
9291
9292   priv->request_mode = mode;
9293
9294   priv->needs_width_request = TRUE;
9295   priv->needs_height_request = TRUE;
9296
9297   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9298
9299   clutter_actor_queue_relayout (self);
9300 }
9301
9302 /**
9303  * clutter_actor_get_request_mode:
9304  * @self: a #ClutterActor
9305  *
9306  * Retrieves the geometry request mode of @self
9307  *
9308  * Return value: the request mode for the actor
9309  *
9310  * Since: 1.2
9311  */
9312 ClutterRequestMode
9313 clutter_actor_get_request_mode (ClutterActor *self)
9314 {
9315   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9316                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9317
9318   return self->priv->request_mode;
9319 }
9320
9321 /* variant of set_width() without checks and without notification
9322  * freeze+thaw, for internal usage only
9323  */
9324 static inline void
9325 clutter_actor_set_width_internal (ClutterActor *self,
9326                                   gfloat        width)
9327 {
9328   if (width >= 0)
9329     {
9330       /* the Stage will use the :min-width to control the minimum
9331        * width to be resized to, so we should not be setting it
9332        * along with the :natural-width
9333        */
9334       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9335         clutter_actor_set_min_width (self, width);
9336
9337       clutter_actor_set_natural_width (self, width);
9338     }
9339   else
9340     {
9341       /* we only unset the :natural-width for the Stage */
9342       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9343         clutter_actor_set_min_width_set (self, FALSE);
9344
9345       clutter_actor_set_natural_width_set (self, FALSE);
9346     }
9347 }
9348
9349 /* variant of set_height() without checks and without notification
9350  * freeze+thaw, for internal usage only
9351  */
9352 static inline void
9353 clutter_actor_set_height_internal (ClutterActor *self,
9354                                    gfloat        height)
9355 {
9356   if (height >= 0)
9357     {
9358       /* see the comment above in set_width_internal() */
9359       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9360         clutter_actor_set_min_height (self, height);
9361
9362       clutter_actor_set_natural_height (self, height);
9363     }
9364   else
9365     {
9366       /* see the comment above in set_width_internal() */
9367       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9368         clutter_actor_set_min_height_set (self, FALSE);
9369
9370       clutter_actor_set_natural_height_set (self, FALSE);
9371     }
9372 }
9373
9374 static void
9375 clutter_actor_set_size_internal (ClutterActor      *self,
9376                                  const ClutterSize *size)
9377 {
9378   if (size != NULL)
9379     {
9380       clutter_actor_set_width_internal (self, size->width);
9381       clutter_actor_set_height_internal (self, size->height);
9382     }
9383   else
9384     {
9385       clutter_actor_set_width_internal (self, -1);
9386       clutter_actor_set_height_internal (self, -1);
9387     }
9388 }
9389
9390 /**
9391  * clutter_actor_set_size:
9392  * @self: A #ClutterActor
9393  * @width: New width of actor in pixels, or -1
9394  * @height: New height of actor in pixels, or -1
9395  *
9396  * Sets the actor's size request in pixels. This overrides any
9397  * "normal" size request the actor would have. For example
9398  * a text actor might normally request the size of the text;
9399  * this function would force a specific size instead.
9400  *
9401  * If @width and/or @height are -1 the actor will use its
9402  * "normal" size request instead of overriding it, i.e.
9403  * you can "unset" the size with -1.
9404  *
9405  * This function sets or unsets both the minimum and natural size.
9406  */
9407 void
9408 clutter_actor_set_size (ClutterActor *self,
9409                         gfloat        width,
9410                         gfloat        height)
9411 {
9412   ClutterSize new_size;
9413
9414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9415
9416   clutter_size_init (&new_size, width, height);
9417
9418   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9419     {
9420       /* minor optimization: if we don't have a duration then we can
9421        * skip the get_size() below, to avoid the chance of going through
9422        * get_preferred_width() and get_preferred_height() just to jump to
9423        * a new desired size
9424        */
9425       if (clutter_actor_get_easing_duration (self) == 0)
9426         {
9427           g_object_freeze_notify (G_OBJECT (self));
9428
9429           clutter_actor_set_size_internal (self, &new_size);
9430
9431           g_object_thaw_notify (G_OBJECT (self));
9432
9433           return;
9434         }
9435       else
9436         {
9437           ClutterSize cur_size;
9438
9439           clutter_size_init (&cur_size,
9440                              clutter_actor_get_width (self),
9441                              clutter_actor_get_height (self));
9442
9443          _clutter_actor_create_transition (self,
9444                                            obj_props[PROP_SIZE],
9445                                            &cur_size,
9446                                            &new_size);
9447         }
9448     }
9449   else
9450     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9451
9452   clutter_actor_queue_relayout (self);
9453 }
9454
9455 /**
9456  * clutter_actor_get_size:
9457  * @self: A #ClutterActor
9458  * @width: (out) (allow-none): return location for the width, or %NULL.
9459  * @height: (out) (allow-none): return location for the height, or %NULL.
9460  *
9461  * This function tries to "do what you mean" and return
9462  * the size an actor will have. If the actor has a valid
9463  * allocation, the allocation will be returned; otherwise,
9464  * the actors natural size request will be returned.
9465  *
9466  * If you care whether you get the request vs. the allocation, you
9467  * should probably call a different function like
9468  * clutter_actor_get_allocation_box() or
9469  * clutter_actor_get_preferred_width().
9470  *
9471  * Since: 0.2
9472  */
9473 void
9474 clutter_actor_get_size (ClutterActor *self,
9475                         gfloat       *width,
9476                         gfloat       *height)
9477 {
9478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9479
9480   if (width)
9481     *width = clutter_actor_get_width (self);
9482
9483   if (height)
9484     *height = clutter_actor_get_height (self);
9485 }
9486
9487 /**
9488  * clutter_actor_get_position:
9489  * @self: a #ClutterActor
9490  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9491  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9492  *
9493  * This function tries to "do what you mean" and tell you where the
9494  * actor is, prior to any transformations. Retrieves the fixed
9495  * position of an actor in pixels, if one has been set; otherwise, if
9496  * the allocation is valid, returns the actor's allocated position;
9497  * otherwise, returns 0,0.
9498  *
9499  * The returned position is in pixels.
9500  *
9501  * Since: 0.6
9502  */
9503 void
9504 clutter_actor_get_position (ClutterActor *self,
9505                             gfloat       *x,
9506                             gfloat       *y)
9507 {
9508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9509
9510   if (x)
9511     *x = clutter_actor_get_x (self);
9512
9513   if (y)
9514     *y = clutter_actor_get_y (self);
9515 }
9516
9517 /**
9518  * clutter_actor_get_transformed_position:
9519  * @self: A #ClutterActor
9520  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9521  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9522  *
9523  * Gets the absolute position of an actor, in pixels relative to the stage.
9524  *
9525  * Since: 0.8
9526  */
9527 void
9528 clutter_actor_get_transformed_position (ClutterActor *self,
9529                                         gfloat       *x,
9530                                         gfloat       *y)
9531 {
9532   ClutterVertex v1;
9533   ClutterVertex v2;
9534
9535   v1.x = v1.y = v1.z = 0;
9536   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9537
9538   if (x)
9539     *x = v2.x;
9540
9541   if (y)
9542     *y = v2.y;
9543 }
9544
9545 /**
9546  * clutter_actor_get_transformed_size:
9547  * @self: A #ClutterActor
9548  * @width: (out) (allow-none): return location for the width, or %NULL
9549  * @height: (out) (allow-none): return location for the height, or %NULL
9550  *
9551  * Gets the absolute size of an actor in pixels, taking into account the
9552  * scaling factors.
9553  *
9554  * If the actor has a valid allocation, the allocated size will be used.
9555  * If the actor has not a valid allocation then the preferred size will
9556  * be transformed and returned.
9557  *
9558  * If you want the transformed allocation, see
9559  * clutter_actor_get_abs_allocation_vertices() instead.
9560  *
9561  * <note>When the actor (or one of its ancestors) is rotated around the
9562  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9563  * as a generic quadrangle; in that case this function returns the size
9564  * of the smallest rectangle that encapsulates the entire quad. Please
9565  * note that in this case no assumptions can be made about the relative
9566  * position of this envelope to the absolute position of the actor, as
9567  * returned by clutter_actor_get_transformed_position(); if you need this
9568  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9569  * to get the coords of the actual quadrangle.</note>
9570  *
9571  * Since: 0.8
9572  */
9573 void
9574 clutter_actor_get_transformed_size (ClutterActor *self,
9575                                     gfloat       *width,
9576                                     gfloat       *height)
9577 {
9578   ClutterActorPrivate *priv;
9579   ClutterVertex v[4];
9580   gfloat x_min, x_max, y_min, y_max;
9581   gint i;
9582
9583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9584
9585   priv = self->priv;
9586
9587   /* if the actor hasn't been allocated yet, get the preferred
9588    * size and transform that
9589    */
9590   if (priv->needs_allocation)
9591     {
9592       gfloat natural_width, natural_height;
9593       ClutterActorBox box;
9594
9595       /* Make a fake allocation to transform.
9596        *
9597        * NB: _clutter_actor_transform_and_project_box expects a box in
9598        * the actor's coordinate space... */
9599
9600       box.x1 = 0;
9601       box.y1 = 0;
9602
9603       natural_width = natural_height = 0;
9604       clutter_actor_get_preferred_size (self, NULL, NULL,
9605                                         &natural_width,
9606                                         &natural_height);
9607
9608       box.x2 = natural_width;
9609       box.y2 = natural_height;
9610
9611       _clutter_actor_transform_and_project_box (self, &box, v);
9612     }
9613   else
9614     clutter_actor_get_abs_allocation_vertices (self, v);
9615
9616   x_min = x_max = v[0].x;
9617   y_min = y_max = v[0].y;
9618
9619   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9620     {
9621       if (v[i].x < x_min)
9622         x_min = v[i].x;
9623
9624       if (v[i].x > x_max)
9625         x_max = v[i].x;
9626
9627       if (v[i].y < y_min)
9628         y_min = v[i].y;
9629
9630       if (v[i].y > y_max)
9631         y_max = v[i].y;
9632     }
9633
9634   if (width)
9635     *width  = x_max - x_min;
9636
9637   if (height)
9638     *height = y_max - y_min;
9639 }
9640
9641 /**
9642  * clutter_actor_get_width:
9643  * @self: A #ClutterActor
9644  *
9645  * Retrieves the width of a #ClutterActor.
9646  *
9647  * If the actor has a valid allocation, this function will return the
9648  * width of the allocated area given to the actor.
9649  *
9650  * If the actor does not have a valid allocation, this function will
9651  * return the actor's natural width, that is the preferred width of
9652  * the actor.
9653  *
9654  * If you care whether you get the preferred width or the width that
9655  * has been assigned to the actor, you should probably call a different
9656  * function like clutter_actor_get_allocation_box() to retrieve the
9657  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9658  * preferred width.
9659  *
9660  * If an actor has a fixed width, for instance a width that has been
9661  * assigned using clutter_actor_set_width(), the width returned will
9662  * be the same value.
9663  *
9664  * Return value: the width of the actor, in pixels
9665  */
9666 gfloat
9667 clutter_actor_get_width (ClutterActor *self)
9668 {
9669   ClutterActorPrivate *priv;
9670
9671   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9672
9673   priv = self->priv;
9674
9675   if (priv->needs_allocation)
9676     {
9677       gfloat natural_width = 0;
9678
9679       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9680         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9681       else
9682         {
9683           gfloat natural_height = 0;
9684
9685           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9686           clutter_actor_get_preferred_width (self, natural_height,
9687                                              NULL,
9688                                              &natural_width);
9689         }
9690
9691       return natural_width;
9692     }
9693   else
9694     return priv->allocation.x2 - priv->allocation.x1;
9695 }
9696
9697 /**
9698  * clutter_actor_get_height:
9699  * @self: A #ClutterActor
9700  *
9701  * Retrieves the height of a #ClutterActor.
9702  *
9703  * If the actor has a valid allocation, this function will return the
9704  * height of the allocated area given to the actor.
9705  *
9706  * If the actor does not have a valid allocation, this function will
9707  * return the actor's natural height, that is the preferred height of
9708  * the actor.
9709  *
9710  * If you care whether you get the preferred height or the height that
9711  * has been assigned to the actor, you should probably call a different
9712  * function like clutter_actor_get_allocation_box() to retrieve the
9713  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9714  * preferred height.
9715  *
9716  * If an actor has a fixed height, for instance a height that has been
9717  * assigned using clutter_actor_set_height(), the height returned will
9718  * be the same value.
9719  *
9720  * Return value: the height of the actor, in pixels
9721  */
9722 gfloat
9723 clutter_actor_get_height (ClutterActor *self)
9724 {
9725   ClutterActorPrivate *priv;
9726
9727   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9728
9729   priv = self->priv;
9730
9731   if (priv->needs_allocation)
9732     {
9733       gfloat natural_height = 0;
9734
9735       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9736         {
9737           gfloat natural_width = 0;
9738
9739           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9740           clutter_actor_get_preferred_height (self, natural_width,
9741                                               NULL, &natural_height);
9742         }
9743       else
9744         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9745
9746       return natural_height;
9747     }
9748   else
9749     return priv->allocation.y2 - priv->allocation.y1;
9750 }
9751
9752 /**
9753  * clutter_actor_set_width:
9754  * @self: A #ClutterActor
9755  * @width: Requested new width for the actor, in pixels, or -1
9756  *
9757  * Forces a width on an actor, causing the actor's preferred width
9758  * and height (if any) to be ignored.
9759  *
9760  * If @width is -1 the actor will use its preferred width request
9761  * instead of overriding it, i.e. you can "unset" the width with -1.
9762  *
9763  * This function sets both the minimum and natural size of the actor.
9764  *
9765  * since: 0.2
9766  */
9767 void
9768 clutter_actor_set_width (ClutterActor *self,
9769                          gfloat        width)
9770 {
9771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9772
9773   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9774     {
9775       float cur_size;
9776
9777       /* minor optimization: if we don't have a duration
9778        * then we can skip the get_width() below, to avoid
9779        * the chance of going through get_preferred_width()
9780        * just to jump to a new desired width.
9781        */
9782       if (clutter_actor_get_easing_duration (self) == 0)
9783         {
9784           g_object_freeze_notify (G_OBJECT (self));
9785
9786           clutter_actor_set_width_internal (self, width);
9787
9788           g_object_thaw_notify (G_OBJECT (self));
9789
9790           return;
9791         }
9792       else
9793         cur_size = clutter_actor_get_width (self);
9794
9795       _clutter_actor_create_transition (self,
9796                                         obj_props[PROP_WIDTH],
9797                                         cur_size,
9798                                         width);
9799     }
9800   else
9801     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9802 }
9803
9804 /**
9805  * clutter_actor_set_height:
9806  * @self: A #ClutterActor
9807  * @height: Requested new height for the actor, in pixels, or -1
9808  *
9809  * Forces a height on an actor, causing the actor's preferred width
9810  * and height (if any) to be ignored.
9811  *
9812  * If @height is -1 the actor will use its preferred height instead of
9813  * overriding it, i.e. you can "unset" the height with -1.
9814  *
9815  * This function sets both the minimum and natural size of the actor.
9816  *
9817  * since: 0.2
9818  */
9819 void
9820 clutter_actor_set_height (ClutterActor *self,
9821                           gfloat        height)
9822 {
9823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9824
9825   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9826     {
9827       float cur_size;
9828
9829       /* see the comment in clutter_actor_set_width() above */
9830       if (clutter_actor_get_easing_duration (self) == 0)
9831         {
9832           g_object_freeze_notify (G_OBJECT (self));
9833
9834           clutter_actor_set_height_internal (self, height);
9835
9836           g_object_thaw_notify (G_OBJECT (self));
9837
9838           return;
9839         }
9840       else
9841         cur_size = clutter_actor_get_height (self);
9842
9843       _clutter_actor_create_transition (self,
9844                                         obj_props[PROP_HEIGHT],
9845                                         cur_size,
9846                                         height);
9847     }
9848   else
9849     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9850 }
9851
9852 static inline void
9853 clutter_actor_set_x_internal (ClutterActor *self,
9854                               float         x)
9855 {
9856   ClutterActorPrivate *priv = self->priv;
9857   ClutterLayoutInfo *linfo;
9858   ClutterActorBox old = { 0, };
9859
9860   linfo = _clutter_actor_get_layout_info (self);
9861
9862   if (priv->position_set && linfo->fixed_pos.x == x)
9863     return;
9864
9865   clutter_actor_store_old_geometry (self, &old);
9866
9867   linfo->fixed_pos.x = x;
9868   clutter_actor_set_fixed_position_set (self, TRUE);
9869
9870   clutter_actor_notify_if_geometry_changed (self, &old);
9871
9872   clutter_actor_queue_relayout (self);
9873 }
9874
9875 static inline void
9876 clutter_actor_set_y_internal (ClutterActor *self,
9877                               float         y)
9878 {
9879   ClutterActorPrivate *priv = self->priv;
9880   ClutterLayoutInfo *linfo;
9881   ClutterActorBox old = { 0, };
9882
9883   linfo = _clutter_actor_get_layout_info (self);
9884
9885   if (priv->position_set && linfo->fixed_pos.y == y)
9886     return;
9887
9888   clutter_actor_store_old_geometry (self, &old);
9889
9890   linfo->fixed_pos.y = y;
9891   clutter_actor_set_fixed_position_set (self, TRUE);
9892
9893   clutter_actor_notify_if_geometry_changed (self, &old);
9894
9895   clutter_actor_queue_relayout (self);
9896 }
9897
9898 static void
9899 clutter_actor_set_position_internal (ClutterActor       *self,
9900                                      const ClutterPoint *position)
9901 {
9902   ClutterActorPrivate *priv = self->priv;
9903   ClutterLayoutInfo *linfo;
9904   ClutterActorBox old = { 0, };
9905
9906   linfo = _clutter_actor_get_layout_info (self);
9907
9908   if (priv->position_set &&
9909       clutter_point_equals (position, &linfo->fixed_pos))
9910     return;
9911
9912   clutter_actor_store_old_geometry (self, &old);
9913
9914   if (position != NULL)
9915     {
9916       linfo->fixed_pos = *position;
9917       clutter_actor_set_fixed_position_set (self, TRUE);
9918     }
9919   else
9920     clutter_actor_set_fixed_position_set (self, FALSE);
9921
9922   clutter_actor_notify_if_geometry_changed (self, &old);
9923
9924   clutter_actor_queue_relayout (self);
9925 }
9926
9927 /**
9928  * clutter_actor_set_x:
9929  * @self: a #ClutterActor
9930  * @x: the actor's position on the X axis
9931  *
9932  * Sets the actor's X coordinate, relative to its parent, in pixels.
9933  *
9934  * Overrides any layout manager and forces a fixed position for
9935  * the actor.
9936  *
9937  * The #ClutterActor:x property is animatable.
9938  *
9939  * Since: 0.6
9940  */
9941 void
9942 clutter_actor_set_x (ClutterActor *self,
9943                      gfloat        x)
9944 {
9945   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9946
9947   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9948     {
9949       float cur_position = clutter_actor_get_x (self);
9950
9951       _clutter_actor_create_transition (self, obj_props[PROP_X],
9952                                         cur_position,
9953                                         x);
9954     }
9955   else
9956     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9957 }
9958
9959 /**
9960  * clutter_actor_set_y:
9961  * @self: a #ClutterActor
9962  * @y: the actor's position on the Y axis
9963  *
9964  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9965  *
9966  * Overrides any layout manager and forces a fixed position for
9967  * the actor.
9968  *
9969  * The #ClutterActor:y property is animatable.
9970  *
9971  * Since: 0.6
9972  */
9973 void
9974 clutter_actor_set_y (ClutterActor *self,
9975                      gfloat        y)
9976 {
9977   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9978
9979   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9980     {
9981       float cur_position = clutter_actor_get_y (self);
9982
9983       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9984                                         cur_position,
9985                                         y);
9986     }
9987   else
9988     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9989 }
9990
9991 /**
9992  * clutter_actor_get_x:
9993  * @self: A #ClutterActor
9994  *
9995  * Retrieves the X coordinate of a #ClutterActor.
9996  *
9997  * This function tries to "do what you mean", by returning the
9998  * correct value depending on the actor's state.
9999  *
10000  * If the actor has a valid allocation, this function will return
10001  * the X coordinate of the origin of the allocation box.
10002  *
10003  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10004  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10005  * function will return that coordinate.
10006  *
10007  * If both the allocation and a fixed position are missing, this function
10008  * will return 0.
10009  *
10010  * Return value: the X coordinate, in pixels, ignoring any
10011  *   transformation (i.e. scaling, rotation)
10012  */
10013 gfloat
10014 clutter_actor_get_x (ClutterActor *self)
10015 {
10016   ClutterActorPrivate *priv;
10017
10018   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10019
10020   priv = self->priv;
10021
10022   if (priv->needs_allocation)
10023     {
10024       if (priv->position_set)
10025         {
10026           const ClutterLayoutInfo *info;
10027
10028           info = _clutter_actor_get_layout_info_or_defaults (self);
10029
10030           return info->fixed_pos.x;
10031         }
10032       else
10033         return 0;
10034     }
10035   else
10036     return priv->allocation.x1;
10037 }
10038
10039 /**
10040  * clutter_actor_get_y:
10041  * @self: A #ClutterActor
10042  *
10043  * Retrieves the Y coordinate of a #ClutterActor.
10044  *
10045  * This function tries to "do what you mean", by returning the
10046  * correct value depending on the actor's state.
10047  *
10048  * If the actor has a valid allocation, this function will return
10049  * the Y coordinate of the origin of the allocation box.
10050  *
10051  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10052  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10053  * function will return that coordinate.
10054  *
10055  * If both the allocation and a fixed position are missing, this function
10056  * will return 0.
10057  *
10058  * Return value: the Y coordinate, in pixels, ignoring any
10059  *   transformation (i.e. scaling, rotation)
10060  */
10061 gfloat
10062 clutter_actor_get_y (ClutterActor *self)
10063 {
10064   ClutterActorPrivate *priv;
10065
10066   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10067
10068   priv = self->priv;
10069
10070   if (priv->needs_allocation)
10071     {
10072       if (priv->position_set)
10073         {
10074           const ClutterLayoutInfo *info;
10075
10076           info = _clutter_actor_get_layout_info_or_defaults (self);
10077
10078           return info->fixed_pos.y;
10079         }
10080       else
10081         return 0;
10082     }
10083   else
10084     return priv->allocation.y1;
10085 }
10086
10087 /**
10088  * clutter_actor_set_scale:
10089  * @self: A #ClutterActor
10090  * @scale_x: double factor to scale actor by horizontally.
10091  * @scale_y: double factor to scale actor by vertically.
10092  *
10093  * Scales an actor with the given factors. The scaling is relative to
10094  * the scale center and the anchor point. The scale center is
10095  * unchanged by this function and defaults to 0,0.
10096  *
10097  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10098  * animatable.
10099  *
10100  * Since: 0.2
10101  */
10102 void
10103 clutter_actor_set_scale (ClutterActor *self,
10104                          gdouble       scale_x,
10105                          gdouble       scale_y)
10106 {
10107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10108
10109   g_object_freeze_notify (G_OBJECT (self));
10110
10111   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10112   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10113
10114   g_object_thaw_notify (G_OBJECT (self));
10115 }
10116
10117 /**
10118  * clutter_actor_set_scale_full:
10119  * @self: A #ClutterActor
10120  * @scale_x: double factor to scale actor by horizontally.
10121  * @scale_y: double factor to scale actor by vertically.
10122  * @center_x: X coordinate of the center of the scale.
10123  * @center_y: Y coordinate of the center of the scale
10124  *
10125  * Scales an actor with the given factors around the given center
10126  * point. The center point is specified in pixels relative to the
10127  * anchor point (usually the top left corner of the actor).
10128  *
10129  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10130  * are animatable.
10131  *
10132  * Since: 1.0
10133  */
10134 void
10135 clutter_actor_set_scale_full (ClutterActor *self,
10136                               gdouble       scale_x,
10137                               gdouble       scale_y,
10138                               gfloat        center_x,
10139                               gfloat        center_y)
10140 {
10141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10142
10143   g_object_freeze_notify (G_OBJECT (self));
10144
10145   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10146   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10147   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10148   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10149
10150   g_object_thaw_notify (G_OBJECT (self));
10151 }
10152
10153 /**
10154  * clutter_actor_set_scale_with_gravity:
10155  * @self: A #ClutterActor
10156  * @scale_x: double factor to scale actor by horizontally.
10157  * @scale_y: double factor to scale actor by vertically.
10158  * @gravity: the location of the scale center expressed as a compass
10159  * direction.
10160  *
10161  * Scales an actor with the given factors around the given
10162  * center point. The center point is specified as one of the compass
10163  * directions in #ClutterGravity. For example, setting it to north
10164  * will cause the top of the actor to remain unchanged and the rest of
10165  * the actor to expand left, right and downwards.
10166  *
10167  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10168  * animatable.
10169  *
10170  * Since: 1.0
10171  */
10172 void
10173 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10174                                       gdouble         scale_x,
10175                                       gdouble         scale_y,
10176                                       ClutterGravity  gravity)
10177 {
10178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10179
10180   g_object_freeze_notify (G_OBJECT (self));
10181
10182   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10183   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10184   clutter_actor_set_scale_gravity (self, gravity);
10185
10186   g_object_thaw_notify (G_OBJECT (self));
10187 }
10188
10189 /**
10190  * clutter_actor_get_scale:
10191  * @self: A #ClutterActor
10192  * @scale_x: (out) (allow-none): Location to store horizonal
10193  *   scale factor, or %NULL.
10194  * @scale_y: (out) (allow-none): Location to store vertical
10195  *   scale factor, or %NULL.
10196  *
10197  * Retrieves an actors scale factors.
10198  *
10199  * Since: 0.2
10200  */
10201 void
10202 clutter_actor_get_scale (ClutterActor *self,
10203                          gdouble      *scale_x,
10204                          gdouble      *scale_y)
10205 {
10206   const ClutterTransformInfo *info;
10207
10208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10209
10210   info = _clutter_actor_get_transform_info_or_defaults (self);
10211
10212   if (scale_x)
10213     *scale_x = info->scale_x;
10214
10215   if (scale_y)
10216     *scale_y = info->scale_y;
10217 }
10218
10219 /**
10220  * clutter_actor_get_scale_center:
10221  * @self: A #ClutterActor
10222  * @center_x: (out) (allow-none): Location to store the X position
10223  *   of the scale center, or %NULL.
10224  * @center_y: (out) (allow-none): Location to store the Y position
10225  *   of the scale center, or %NULL.
10226  *
10227  * Retrieves the scale center coordinate in pixels relative to the top
10228  * left corner of the actor. If the scale center was specified using a
10229  * #ClutterGravity this will calculate the pixel offset using the
10230  * current size of the actor.
10231  *
10232  * Since: 1.0
10233  */
10234 void
10235 clutter_actor_get_scale_center (ClutterActor *self,
10236                                 gfloat       *center_x,
10237                                 gfloat       *center_y)
10238 {
10239   const ClutterTransformInfo *info;
10240
10241   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10242
10243   info = _clutter_actor_get_transform_info_or_defaults (self);
10244
10245   clutter_anchor_coord_get_units (self, &info->scale_center,
10246                                   center_x,
10247                                   center_y,
10248                                   NULL);
10249 }
10250
10251 /**
10252  * clutter_actor_get_scale_gravity:
10253  * @self: A #ClutterActor
10254  *
10255  * Retrieves the scale center as a compass direction. If the scale
10256  * center was specified in pixels or units this will return
10257  * %CLUTTER_GRAVITY_NONE.
10258  *
10259  * Return value: the scale gravity
10260  *
10261  * Since: 1.0
10262  */
10263 ClutterGravity
10264 clutter_actor_get_scale_gravity (ClutterActor *self)
10265 {
10266   const ClutterTransformInfo *info;
10267
10268   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10269
10270   info = _clutter_actor_get_transform_info_or_defaults (self);
10271
10272   return clutter_anchor_coord_get_gravity (&info->scale_center);
10273 }
10274
10275 static inline void
10276 clutter_actor_set_opacity_internal (ClutterActor *self,
10277                                     guint8        opacity)
10278 {
10279   ClutterActorPrivate *priv = self->priv;
10280
10281   if (priv->opacity != opacity)
10282     {
10283       priv->opacity = opacity;
10284
10285       /* Queue a redraw from the flatten effect so that it can use
10286          its cached image if available instead of having to redraw the
10287          actual actor. If it doesn't end up using the FBO then the
10288          effect is still able to continue the paint anyway. If there
10289          is no flatten effect yet then this is equivalent to queueing
10290          a full redraw */
10291       _clutter_actor_queue_redraw_full (self,
10292                                         0, /* flags */
10293                                         NULL, /* clip */
10294                                         priv->flatten_effect);
10295
10296       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10297     }
10298 }
10299
10300 /**
10301  * clutter_actor_set_opacity:
10302  * @self: A #ClutterActor
10303  * @opacity: New opacity value for the actor.
10304  *
10305  * Sets the actor's opacity, with zero being completely transparent and
10306  * 255 (0xff) being fully opaque.
10307  *
10308  * The #ClutterActor:opacity property is animatable.
10309  */
10310 void
10311 clutter_actor_set_opacity (ClutterActor *self,
10312                            guint8        opacity)
10313 {
10314   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10315
10316   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10317     {
10318       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10319                                         self->priv->opacity,
10320                                         opacity);
10321     }
10322   else
10323     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10324 }
10325
10326 /*
10327  * clutter_actor_get_paint_opacity_internal:
10328  * @self: a #ClutterActor
10329  *
10330  * Retrieves the absolute opacity of the actor, as it appears on the stage
10331  *
10332  * This function does not do type checks
10333  *
10334  * Return value: the absolute opacity of the actor
10335  */
10336 static guint8
10337 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10338 {
10339   ClutterActorPrivate *priv = self->priv;
10340   ClutterActor *parent;
10341
10342   /* override the top-level opacity to always be 255; even in
10343    * case of ClutterStage:use-alpha being TRUE we want the rest
10344    * of the scene to be painted
10345    */
10346   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10347     return 255;
10348
10349   if (priv->opacity_override >= 0)
10350     return priv->opacity_override;
10351
10352   parent = priv->parent;
10353
10354   /* Factor in the actual actors opacity with parents */
10355   if (parent != NULL)
10356     {
10357       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10358
10359       if (opacity != 0xff)
10360         return (opacity * priv->opacity) / 0xff;
10361     }
10362
10363   return priv->opacity;
10364
10365 }
10366
10367 /**
10368  * clutter_actor_get_paint_opacity:
10369  * @self: A #ClutterActor
10370  *
10371  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10372  *
10373  * This function traverses the hierarchy chain and composites the opacity of
10374  * the actor with that of its parents.
10375  *
10376  * This function is intended for subclasses to use in the paint virtual
10377  * function, to paint themselves with the correct opacity.
10378  *
10379  * Return value: The actor opacity value.
10380  *
10381  * Since: 0.8
10382  */
10383 guint8
10384 clutter_actor_get_paint_opacity (ClutterActor *self)
10385 {
10386   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10387
10388   return clutter_actor_get_paint_opacity_internal (self);
10389 }
10390
10391 /**
10392  * clutter_actor_get_opacity:
10393  * @self: a #ClutterActor
10394  *
10395  * Retrieves the opacity value of an actor, as set by
10396  * clutter_actor_set_opacity().
10397  *
10398  * For retrieving the absolute opacity of the actor inside a paint
10399  * virtual function, see clutter_actor_get_paint_opacity().
10400  *
10401  * Return value: the opacity of the actor
10402  */
10403 guint8
10404 clutter_actor_get_opacity (ClutterActor *self)
10405 {
10406   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10407
10408   return self->priv->opacity;
10409 }
10410
10411 /**
10412  * clutter_actor_set_offscreen_redirect:
10413  * @self: A #ClutterActor
10414  * @redirect: New offscreen redirect flags for the actor.
10415  *
10416  * Defines the circumstances where the actor should be redirected into
10417  * an offscreen image. The offscreen image is used to flatten the
10418  * actor into a single image while painting for two main reasons.
10419  * Firstly, when the actor is painted a second time without any of its
10420  * contents changing it can simply repaint the cached image without
10421  * descending further down the actor hierarchy. Secondly, it will make
10422  * the opacity look correct even if there are overlapping primitives
10423  * in the actor.
10424  *
10425  * Caching the actor could in some cases be a performance win and in
10426  * some cases be a performance lose so it is important to determine
10427  * which value is right for an actor before modifying this value. For
10428  * example, there is never any reason to flatten an actor that is just
10429  * a single texture (such as a #ClutterTexture) because it is
10430  * effectively already cached in an image so the offscreen would be
10431  * redundant. Also if the actor contains primitives that are far apart
10432  * with a large transparent area in the middle (such as a large
10433  * CluterGroup with a small actor in the top left and a small actor in
10434  * the bottom right) then the cached image will contain the entire
10435  * image of the large area and the paint will waste time blending all
10436  * of the transparent pixels in the middle.
10437  *
10438  * The default method of implementing opacity on a container simply
10439  * forwards on the opacity to all of the children. If the children are
10440  * overlapping then it will appear as if they are two separate glassy
10441  * objects and there will be a break in the color where they
10442  * overlap. By redirecting to an offscreen buffer it will be as if the
10443  * two opaque objects are combined into one and then made transparent
10444  * which is usually what is expected.
10445  *
10446  * The image below demonstrates the difference between redirecting and
10447  * not. The image shows two Clutter groups, each containing a red and
10448  * a green rectangle which overlap. The opacity on the group is set to
10449  * 128 (which is 50%). When the offscreen redirect is not used, the
10450  * red rectangle can be seen through the blue rectangle as if the two
10451  * rectangles were separately transparent. When the redirect is used
10452  * the group as a whole is transparent instead so the red rectangle is
10453  * not visible where they overlap.
10454  *
10455  * <figure id="offscreen-redirect">
10456  *   <title>Sample of using an offscreen redirect for transparency</title>
10457  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10458  * </figure>
10459  *
10460  * The default value for this property is 0, so we effectively will
10461  * never redirect an actor offscreen by default. This means that there
10462  * are times that transparent actors may look glassy as described
10463  * above. The reason this is the default is because there is a
10464  * performance trade off between quality and performance here. In many
10465  * cases the default form of glassy opacity looks good enough, but if
10466  * it's not you will need to set the
10467  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10468  * redirection for opacity.
10469  *
10470  * Custom actors that don't contain any overlapping primitives are
10471  * recommended to override the has_overlaps() virtual to return %FALSE
10472  * for maximum efficiency.
10473  *
10474  * Since: 1.8
10475  */
10476 void
10477 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10478                                       ClutterOffscreenRedirect redirect)
10479 {
10480   ClutterActorPrivate *priv;
10481
10482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10483
10484   priv = self->priv;
10485
10486   if (priv->offscreen_redirect != redirect)
10487     {
10488       priv->offscreen_redirect = redirect;
10489
10490       /* Queue a redraw from the effect so that it can use its cached
10491          image if available instead of having to redraw the actual
10492          actor. If it doesn't end up using the FBO then the effect is
10493          still able to continue the paint anyway. If there is no
10494          effect then this is equivalent to queuing a full redraw */
10495       _clutter_actor_queue_redraw_full (self,
10496                                         0, /* flags */
10497                                         NULL, /* clip */
10498                                         priv->flatten_effect);
10499
10500       g_object_notify_by_pspec (G_OBJECT (self),
10501                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10502     }
10503 }
10504
10505 /**
10506  * clutter_actor_get_offscreen_redirect:
10507  * @self: a #ClutterActor
10508  *
10509  * Retrieves whether to redirect the actor to an offscreen buffer, as
10510  * set by clutter_actor_set_offscreen_redirect().
10511  *
10512  * Return value: the value of the offscreen-redirect property of the actor
10513  *
10514  * Since: 1.8
10515  */
10516 ClutterOffscreenRedirect
10517 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10518 {
10519   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10520
10521   return self->priv->offscreen_redirect;
10522 }
10523
10524 /**
10525  * clutter_actor_set_name:
10526  * @self: A #ClutterActor
10527  * @name: Textual tag to apply to actor
10528  *
10529  * Sets the given name to @self. The name can be used to identify
10530  * a #ClutterActor.
10531  */
10532 void
10533 clutter_actor_set_name (ClutterActor *self,
10534                         const gchar  *name)
10535 {
10536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10537
10538   g_free (self->priv->name);
10539   self->priv->name = g_strdup (name);
10540
10541   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10542 }
10543
10544 /**
10545  * clutter_actor_get_name:
10546  * @self: A #ClutterActor
10547  *
10548  * Retrieves the name of @self.
10549  *
10550  * Return value: the name of the actor, or %NULL. The returned string is
10551  *   owned by the actor and should not be modified or freed.
10552  */
10553 const gchar *
10554 clutter_actor_get_name (ClutterActor *self)
10555 {
10556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10557
10558   return self->priv->name;
10559 }
10560
10561 /**
10562  * clutter_actor_get_gid:
10563  * @self: A #ClutterActor
10564  *
10565  * Retrieves the unique id for @self.
10566  *
10567  * Return value: Globally unique value for this object instance.
10568  *
10569  * Since: 0.6
10570  *
10571  * Deprecated: 1.8: The id is not used any longer.
10572  */
10573 guint32
10574 clutter_actor_get_gid (ClutterActor *self)
10575 {
10576   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10577
10578   return self->priv->id;
10579 }
10580
10581 static inline void
10582 clutter_actor_set_depth_internal (ClutterActor *self,
10583                                   float         depth)
10584 {
10585   ClutterTransformInfo *info;
10586
10587   info = _clutter_actor_get_transform_info (self);
10588
10589   if (info->depth != depth)
10590     {
10591       /* Sets Z value - XXX 2.0: should we invert? */
10592       info->depth = depth;
10593
10594       self->priv->transform_valid = FALSE;
10595
10596       /* FIXME - remove this crap; sadly, there are still containers
10597        * in Clutter that depend on this utter brain damage
10598        */
10599       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10600
10601       clutter_actor_queue_redraw (self);
10602
10603       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10604     }
10605 }
10606
10607 /**
10608  * clutter_actor_set_depth:
10609  * @self: a #ClutterActor
10610  * @depth: Z co-ord
10611  *
10612  * Sets the Z coordinate of @self to @depth.
10613  *
10614  * The unit used by @depth is dependant on the perspective setup. See
10615  * also clutter_stage_set_perspective().
10616  */
10617 void
10618 clutter_actor_set_depth (ClutterActor *self,
10619                          gfloat        depth)
10620 {
10621   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10622
10623   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10624     {
10625       const ClutterTransformInfo *info;
10626
10627       info = _clutter_actor_get_transform_info_or_defaults (self);
10628
10629       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10630                                         info->depth,
10631                                         depth);
10632     }
10633   else
10634     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10635
10636   clutter_actor_queue_redraw (self);
10637 }
10638
10639 /**
10640  * clutter_actor_get_depth:
10641  * @self: a #ClutterActor
10642  *
10643  * Retrieves the depth of @self.
10644  *
10645  * Return value: the depth of the actor
10646  */
10647 gfloat
10648 clutter_actor_get_depth (ClutterActor *self)
10649 {
10650   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10651
10652   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10653 }
10654
10655 /**
10656  * clutter_actor_set_rotation:
10657  * @self: a #ClutterActor
10658  * @axis: the axis of rotation
10659  * @angle: the angle of rotation
10660  * @x: X coordinate of the rotation center
10661  * @y: Y coordinate of the rotation center
10662  * @z: Z coordinate of the rotation center
10663  *
10664  * Sets the rotation angle of @self around the given axis.
10665  *
10666  * The rotation center coordinates used depend on the value of @axis:
10667  * <itemizedlist>
10668  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10669  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10670  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10671  * </itemizedlist>
10672  *
10673  * The rotation coordinates are relative to the anchor point of the
10674  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10675  * point is set, the upper left corner is assumed as the origin.
10676  *
10677  * Since: 0.8
10678  */
10679 void
10680 clutter_actor_set_rotation (ClutterActor      *self,
10681                             ClutterRotateAxis  axis,
10682                             gdouble            angle,
10683                             gfloat             x,
10684                             gfloat             y,
10685                             gfloat             z)
10686 {
10687   ClutterVertex v;
10688
10689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10690
10691   v.x = x;
10692   v.y = y;
10693   v.z = z;
10694
10695   g_object_freeze_notify (G_OBJECT (self));
10696
10697   clutter_actor_set_rotation_angle (self, axis, angle);
10698   clutter_actor_set_rotation_center_internal (self, axis, &v);
10699
10700   g_object_thaw_notify (G_OBJECT (self));
10701 }
10702
10703 /**
10704  * clutter_actor_set_z_rotation_from_gravity:
10705  * @self: a #ClutterActor
10706  * @angle: the angle of rotation
10707  * @gravity: the center point of the rotation
10708  *
10709  * Sets the rotation angle of @self around the Z axis using the center
10710  * point specified as a compass point. For example to rotate such that
10711  * the center of the actor remains static you can use
10712  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10713  * will move accordingly.
10714  *
10715  * Since: 1.0
10716  */
10717 void
10718 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10719                                            gdouble         angle,
10720                                            ClutterGravity  gravity)
10721 {
10722   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10723
10724   if (gravity == CLUTTER_GRAVITY_NONE)
10725     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10726   else
10727     {
10728       GObject *obj = G_OBJECT (self);
10729       ClutterTransformInfo *info;
10730
10731       info = _clutter_actor_get_transform_info (self);
10732
10733       g_object_freeze_notify (obj);
10734
10735       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10736
10737       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10738       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10739       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10740
10741       g_object_thaw_notify (obj);
10742     }
10743 }
10744
10745 /**
10746  * clutter_actor_get_rotation:
10747  * @self: a #ClutterActor
10748  * @axis: the axis of rotation
10749  * @x: (out): return value for the X coordinate of the center of rotation
10750  * @y: (out): return value for the Y coordinate of the center of rotation
10751  * @z: (out): return value for the Z coordinate of the center of rotation
10752  *
10753  * Retrieves the angle and center of rotation on the given axis,
10754  * set using clutter_actor_set_rotation().
10755  *
10756  * Return value: the angle of rotation
10757  *
10758  * Since: 0.8
10759  */
10760 gdouble
10761 clutter_actor_get_rotation (ClutterActor      *self,
10762                             ClutterRotateAxis  axis,
10763                             gfloat            *x,
10764                             gfloat            *y,
10765                             gfloat            *z)
10766 {
10767   const ClutterTransformInfo *info;
10768   const AnchorCoord *anchor_coord;
10769   gdouble retval = 0;
10770
10771   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10772
10773   info = _clutter_actor_get_transform_info_or_defaults (self);
10774
10775   switch (axis)
10776     {
10777     case CLUTTER_X_AXIS:
10778       anchor_coord = &info->rx_center;
10779       retval = info->rx_angle;
10780       break;
10781
10782     case CLUTTER_Y_AXIS:
10783       anchor_coord = &info->ry_center;
10784       retval = info->ry_angle;
10785       break;
10786
10787     case CLUTTER_Z_AXIS:
10788       anchor_coord = &info->rz_center;
10789       retval = info->rz_angle;
10790       break;
10791
10792     default:
10793       anchor_coord = NULL;
10794       retval = 0.0;
10795       break;
10796     }
10797
10798   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10799
10800   return retval;
10801 }
10802
10803 /**
10804  * clutter_actor_get_z_rotation_gravity:
10805  * @self: A #ClutterActor
10806  *
10807  * Retrieves the center for the rotation around the Z axis as a
10808  * compass direction. If the center was specified in pixels or units
10809  * this will return %CLUTTER_GRAVITY_NONE.
10810  *
10811  * Return value: the Z rotation center
10812  *
10813  * Since: 1.0
10814  */
10815 ClutterGravity
10816 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10817 {
10818   const ClutterTransformInfo *info;
10819
10820   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10821
10822   info = _clutter_actor_get_transform_info_or_defaults (self);
10823
10824   return clutter_anchor_coord_get_gravity (&info->rz_center);
10825 }
10826
10827 /**
10828  * clutter_actor_set_clip:
10829  * @self: A #ClutterActor
10830  * @xoff: X offset of the clip rectangle
10831  * @yoff: Y offset of the clip rectangle
10832  * @width: Width of the clip rectangle
10833  * @height: Height of the clip rectangle
10834  *
10835  * Sets clip area for @self. The clip area is always computed from the
10836  * upper left corner of the actor, even if the anchor point is set
10837  * otherwise.
10838  *
10839  * Since: 0.6
10840  */
10841 void
10842 clutter_actor_set_clip (ClutterActor *self,
10843                         gfloat        xoff,
10844                         gfloat        yoff,
10845                         gfloat        width,
10846                         gfloat        height)
10847 {
10848   ClutterActorPrivate *priv;
10849
10850   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10851
10852   priv = self->priv;
10853
10854   if (priv->has_clip &&
10855       priv->clip.x == xoff &&
10856       priv->clip.y == yoff &&
10857       priv->clip.width == width &&
10858       priv->clip.height == height)
10859     return;
10860
10861   priv->clip.x = xoff;
10862   priv->clip.y = yoff;
10863   priv->clip.width = width;
10864   priv->clip.height = height;
10865
10866   priv->has_clip = TRUE;
10867
10868   clutter_actor_queue_redraw (self);
10869
10870   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10871   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10872 }
10873
10874 /**
10875  * clutter_actor_remove_clip:
10876  * @self: A #ClutterActor
10877  *
10878  * Removes clip area from @self.
10879  */
10880 void
10881 clutter_actor_remove_clip (ClutterActor *self)
10882 {
10883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10884
10885   if (!self->priv->has_clip)
10886     return;
10887
10888   self->priv->has_clip = FALSE;
10889
10890   clutter_actor_queue_redraw (self);
10891
10892   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10893 }
10894
10895 /**
10896  * clutter_actor_has_clip:
10897  * @self: a #ClutterActor
10898  *
10899  * Determines whether the actor has a clip area set or not.
10900  *
10901  * Return value: %TRUE if the actor has a clip area set.
10902  *
10903  * Since: 0.1.1
10904  */
10905 gboolean
10906 clutter_actor_has_clip (ClutterActor *self)
10907 {
10908   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10909
10910   return self->priv->has_clip;
10911 }
10912
10913 /**
10914  * clutter_actor_get_clip:
10915  * @self: a #ClutterActor
10916  * @xoff: (out) (allow-none): return location for the X offset of
10917  *   the clip rectangle, or %NULL
10918  * @yoff: (out) (allow-none): return location for the Y offset of
10919  *   the clip rectangle, or %NULL
10920  * @width: (out) (allow-none): return location for the width of
10921  *   the clip rectangle, or %NULL
10922  * @height: (out) (allow-none): return location for the height of
10923  *   the clip rectangle, or %NULL
10924  *
10925  * Gets the clip area for @self, if any is set
10926  *
10927  * Since: 0.6
10928  */
10929 void
10930 clutter_actor_get_clip (ClutterActor *self,
10931                         gfloat       *xoff,
10932                         gfloat       *yoff,
10933                         gfloat       *width,
10934                         gfloat       *height)
10935 {
10936   ClutterActorPrivate *priv;
10937
10938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10939
10940   priv = self->priv;
10941
10942   if (!priv->has_clip)
10943     return;
10944
10945   if (xoff != NULL)
10946     *xoff = priv->clip.x;
10947
10948   if (yoff != NULL)
10949     *yoff = priv->clip.y;
10950
10951   if (width != NULL)
10952     *width = priv->clip.width;
10953
10954   if (height != NULL)
10955     *height = priv->clip.height;
10956 }
10957
10958 /**
10959  * clutter_actor_get_children:
10960  * @self: a #ClutterActor
10961  *
10962  * Retrieves the list of children of @self.
10963  *
10964  * Return value: (transfer container) (element-type ClutterActor): A newly
10965  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10966  *   done.
10967  *
10968  * Since: 1.10
10969  */
10970 GList *
10971 clutter_actor_get_children (ClutterActor *self)
10972 {
10973   ClutterActor *iter;
10974   GList *res;
10975
10976   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10977
10978   /* we walk the list backward so that we can use prepend(),
10979    * which is O(1)
10980    */
10981   for (iter = self->priv->last_child, res = NULL;
10982        iter != NULL;
10983        iter = iter->priv->prev_sibling)
10984     {
10985       res = g_list_prepend (res, iter);
10986     }
10987
10988   return res;
10989 }
10990
10991 /*< private >
10992  * insert_child_at_depth:
10993  * @self: a #ClutterActor
10994  * @child: a #ClutterActor
10995  *
10996  * Inserts @child inside the list of children held by @self, using
10997  * the depth as the insertion criteria.
10998  *
10999  * This sadly makes the insertion not O(1), but we can keep the
11000  * list sorted so that the painters algorithm we use for painting
11001  * the children will work correctly.
11002  */
11003 static void
11004 insert_child_at_depth (ClutterActor *self,
11005                        ClutterActor *child,
11006                        gpointer      dummy G_GNUC_UNUSED)
11007 {
11008   ClutterActor *iter;
11009   float child_depth;
11010
11011   child->priv->parent = self;
11012
11013   child_depth =
11014     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11015
11016   /* special-case the first child */
11017   if (self->priv->n_children == 0)
11018     {
11019       self->priv->first_child = child;
11020       self->priv->last_child = child;
11021
11022       child->priv->next_sibling = NULL;
11023       child->priv->prev_sibling = NULL;
11024
11025       return;
11026     }
11027
11028   /* Find the right place to insert the child so that it will still be
11029      sorted and the child will be after all of the actors at the same
11030      dept */
11031   for (iter = self->priv->first_child;
11032        iter != NULL;
11033        iter = iter->priv->next_sibling)
11034     {
11035       float iter_depth;
11036
11037       iter_depth =
11038         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11039
11040       if (iter_depth > child_depth)
11041         break;
11042     }
11043
11044   if (iter != NULL)
11045     {
11046       ClutterActor *tmp = iter->priv->prev_sibling;
11047
11048       if (tmp != NULL)
11049         tmp->priv->next_sibling = child;
11050
11051       /* Insert the node before the found one */
11052       child->priv->prev_sibling = iter->priv->prev_sibling;
11053       child->priv->next_sibling = iter;
11054       iter->priv->prev_sibling = child;
11055     }
11056   else
11057     {
11058       ClutterActor *tmp = self->priv->last_child;
11059
11060       if (tmp != NULL)
11061         tmp->priv->next_sibling = child;
11062
11063       /* insert the node at the end of the list */
11064       child->priv->prev_sibling = self->priv->last_child;
11065       child->priv->next_sibling = NULL;
11066     }
11067
11068   if (child->priv->prev_sibling == NULL)
11069     self->priv->first_child = child;
11070
11071   if (child->priv->next_sibling == NULL)
11072     self->priv->last_child = child;
11073 }
11074
11075 static void
11076 insert_child_at_index (ClutterActor *self,
11077                        ClutterActor *child,
11078                        gpointer      data_)
11079 {
11080   gint index_ = GPOINTER_TO_INT (data_);
11081
11082   child->priv->parent = self;
11083
11084   if (index_ == 0)
11085     {
11086       ClutterActor *tmp = self->priv->first_child;
11087
11088       if (tmp != NULL)
11089         tmp->priv->prev_sibling = child;
11090
11091       child->priv->prev_sibling = NULL;
11092       child->priv->next_sibling = tmp;
11093     }
11094   else if (index_ < 0 || index_ >= self->priv->n_children)
11095     {
11096       ClutterActor *tmp = self->priv->last_child;
11097
11098       if (tmp != NULL)
11099         tmp->priv->next_sibling = child;
11100
11101       child->priv->prev_sibling = tmp;
11102       child->priv->next_sibling = NULL;
11103     }
11104   else
11105     {
11106       ClutterActor *iter;
11107       int i;
11108
11109       for (iter = self->priv->first_child, i = 0;
11110            iter != NULL;
11111            iter = iter->priv->next_sibling, i += 1)
11112         {
11113           if (index_ == i)
11114             {
11115               ClutterActor *tmp = iter->priv->prev_sibling;
11116
11117               child->priv->prev_sibling = tmp;
11118               child->priv->next_sibling = iter;
11119
11120               iter->priv->prev_sibling = child;
11121
11122               if (tmp != NULL)
11123                 tmp->priv->next_sibling = child;
11124
11125               break;
11126             }
11127         }
11128     }
11129
11130   if (child->priv->prev_sibling == NULL)
11131     self->priv->first_child = child;
11132
11133   if (child->priv->next_sibling == NULL)
11134     self->priv->last_child = child;
11135 }
11136
11137 static void
11138 insert_child_above (ClutterActor *self,
11139                     ClutterActor *child,
11140                     gpointer      data)
11141 {
11142   ClutterActor *sibling = data;
11143
11144   child->priv->parent = self;
11145
11146   if (sibling == NULL)
11147     sibling = self->priv->last_child;
11148
11149   child->priv->prev_sibling = sibling;
11150
11151   if (sibling != NULL)
11152     {
11153       ClutterActor *tmp = sibling->priv->next_sibling;
11154
11155       child->priv->next_sibling = tmp;
11156
11157       if (tmp != NULL)
11158         tmp->priv->prev_sibling = child;
11159
11160       sibling->priv->next_sibling = child;
11161     }
11162   else
11163     child->priv->next_sibling = NULL;
11164
11165   if (child->priv->prev_sibling == NULL)
11166     self->priv->first_child = child;
11167
11168   if (child->priv->next_sibling == NULL)
11169     self->priv->last_child = child;
11170 }
11171
11172 static void
11173 insert_child_below (ClutterActor *self,
11174                     ClutterActor *child,
11175                     gpointer      data)
11176 {
11177   ClutterActor *sibling = data;
11178
11179   child->priv->parent = self;
11180
11181   if (sibling == NULL)
11182     sibling = self->priv->first_child;
11183
11184   child->priv->next_sibling = sibling;
11185
11186   if (sibling != NULL)
11187     {
11188       ClutterActor *tmp = sibling->priv->prev_sibling;
11189
11190       child->priv->prev_sibling = tmp;
11191
11192       if (tmp != NULL)
11193         tmp->priv->next_sibling = child;
11194
11195       sibling->priv->prev_sibling = child;
11196     }
11197   else
11198     child->priv->prev_sibling = NULL;
11199
11200   if (child->priv->prev_sibling == NULL)
11201     self->priv->first_child = child;
11202
11203   if (child->priv->next_sibling == NULL)
11204     self->priv->last_child = child;
11205 }
11206
11207 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11208                                            ClutterActor *child,
11209                                            gpointer      data);
11210
11211 typedef enum {
11212   ADD_CHILD_CREATE_META        = 1 << 0,
11213   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11214   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11215   ADD_CHILD_CHECK_STATE        = 1 << 3,
11216   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11217   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11218
11219   /* default flags for public API */
11220   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11221                                ADD_CHILD_EMIT_PARENT_SET |
11222                                ADD_CHILD_EMIT_ACTOR_ADDED |
11223                                ADD_CHILD_CHECK_STATE |
11224                                ADD_CHILD_NOTIFY_FIRST_LAST |
11225                                ADD_CHILD_SHOW_ON_SET_PARENT,
11226
11227   /* flags for legacy/deprecated API */
11228   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11229                                ADD_CHILD_CHECK_STATE |
11230                                ADD_CHILD_NOTIFY_FIRST_LAST |
11231                                ADD_CHILD_SHOW_ON_SET_PARENT
11232 } ClutterActorAddChildFlags;
11233
11234 /*< private >
11235  * clutter_actor_add_child_internal:
11236  * @self: a #ClutterActor
11237  * @child: a #ClutterActor
11238  * @flags: control flags for actions
11239  * @add_func: delegate function
11240  * @data: (closure): data to pass to @add_func
11241  *
11242  * Adds @child to the list of children of @self.
11243  *
11244  * The actual insertion inside the list is delegated to @add_func: this
11245  * function will just set up the state, perform basic checks, and emit
11246  * signals.
11247  *
11248  * The @flags argument is used to perform additional operations.
11249  */
11250 static inline void
11251 clutter_actor_add_child_internal (ClutterActor              *self,
11252                                   ClutterActor              *child,
11253                                   ClutterActorAddChildFlags  flags,
11254                                   ClutterActorAddChildFunc   add_func,
11255                                   gpointer                   data)
11256 {
11257   ClutterTextDirection text_dir;
11258   gboolean create_meta;
11259   gboolean emit_parent_set, emit_actor_added;
11260   gboolean check_state;
11261   gboolean notify_first_last;
11262   gboolean show_on_set_parent;
11263   ClutterActor *old_first_child, *old_last_child;
11264
11265   if (child->priv->parent != NULL)
11266     {
11267       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11268                  "use clutter_actor_remove_child() first.",
11269                  _clutter_actor_get_debug_name (child),
11270                  _clutter_actor_get_debug_name (child->priv->parent));
11271       return;
11272     }
11273
11274   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11275     {
11276       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11277                  "a child of another actor.",
11278                  _clutter_actor_get_debug_name (child));
11279       return;
11280     }
11281
11282 #if 0
11283   /* XXX - this check disallows calling methods that change the stacking
11284    * order within the destruction sequence, by triggering a critical
11285    * warning first, and leaving the actor in an undefined state, which
11286    * then ends up being caught by an assertion.
11287    *
11288    * the reproducible sequence is:
11289    *
11290    *   - actor gets destroyed;
11291    *   - another actor, linked to the first, will try to change the
11292    *     stacking order of the first actor;
11293    *   - changing the stacking order is a composite operation composed
11294    *     by the following steps:
11295    *     1. ref() the child;
11296    *     2. remove_child_internal(), which removes the reference;
11297    *     3. add_child_internal(), which adds a reference;
11298    *   - the state of the actor is not changed between (2) and (3), as
11299    *     it could be an expensive recomputation;
11300    *   - if (3) bails out, then the actor is in an undefined state, but
11301    *     still alive;
11302    *   - the destruction sequence terminates, but the actor is unparented
11303    *     while its state indicates being parented instead.
11304    *   - assertion failure.
11305    *
11306    * the obvious fix would be to decompose each set_child_*_sibling()
11307    * method into proper remove_child()/add_child(), with state validation;
11308    * this may cause excessive work, though, and trigger a cascade of other
11309    * bugs in code that assumes that a change in the stacking order is an
11310    * atomic operation.
11311    *
11312    * another potential fix is to just remove this check here, and let
11313    * code doing stacking order changes inside the destruction sequence
11314    * of an actor continue doing the work.
11315    *
11316    * the third fix is to silently bail out early from every
11317    * set_child_*_sibling() and set_child_at_index() method, and avoid
11318    * doing work.
11319    *
11320    * I have a preference for the second solution, since it involves the
11321    * least amount of work, and the least amount of code duplication.
11322    *
11323    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11324    */
11325   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11326     {
11327       g_warning ("The actor '%s' is currently being destroyed, and "
11328                  "cannot be added as a child of another actor.",
11329                  _clutter_actor_get_debug_name (child));
11330       return;
11331     }
11332 #endif
11333
11334   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11335   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11336   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11337   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11338   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11339   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11340
11341   old_first_child = self->priv->first_child;
11342   old_last_child = self->priv->last_child;
11343
11344   g_object_freeze_notify (G_OBJECT (self));
11345
11346   if (create_meta)
11347     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11348
11349   g_object_ref_sink (child);
11350   child->priv->parent = NULL;
11351   child->priv->next_sibling = NULL;
11352   child->priv->prev_sibling = NULL;
11353
11354   /* delegate the actual insertion */
11355   add_func (self, child, data);
11356
11357   g_assert (child->priv->parent == self);
11358
11359   self->priv->n_children += 1;
11360
11361   self->priv->age += 1;
11362
11363   /* if push_internal() has been called then we automatically set
11364    * the flag on the actor
11365    */
11366   if (self->priv->internal_child)
11367     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11368
11369   /* children may cause their parent to expand, if they are set
11370    * to expand; if a child is not expanded then it cannot change
11371    * its parent's state. any further change later on will queue
11372    * an expand state check.
11373    *
11374    * this check, with the initial state of the needs_compute_expand
11375    * flag set to FALSE, should avoid recomputing the expand flags
11376    * state while building the actor tree.
11377    */
11378   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11379       (child->priv->needs_compute_expand ||
11380        child->priv->needs_x_expand ||
11381        child->priv->needs_y_expand))
11382     {
11383       clutter_actor_queue_compute_expand (self);
11384     }
11385
11386   /* clutter_actor_reparent() will emit ::parent-set for us */
11387   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11388     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11389
11390   if (check_state)
11391     {
11392       /* If parent is mapped or realized, we need to also be mapped or
11393        * realized once we're inside the parent.
11394        */
11395       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11396
11397       /* propagate the parent's text direction to the child */
11398       text_dir = clutter_actor_get_text_direction (self);
11399       clutter_actor_set_text_direction (child, text_dir);
11400     }
11401
11402   if (show_on_set_parent && child->priv->show_on_set_parent)
11403     clutter_actor_show (child);
11404
11405   if (CLUTTER_ACTOR_IS_MAPPED (child))
11406     clutter_actor_queue_redraw (child);
11407
11408   /* maintain the invariant that if an actor needs layout,
11409    * its parents do as well
11410    */
11411   if (child->priv->needs_width_request ||
11412       child->priv->needs_height_request ||
11413       child->priv->needs_allocation)
11414     {
11415       /* we work around the short-circuiting we do
11416        * in clutter_actor_queue_relayout() since we
11417        * want to force a relayout
11418        */
11419       child->priv->needs_width_request = TRUE;
11420       child->priv->needs_height_request = TRUE;
11421       child->priv->needs_allocation = TRUE;
11422
11423       clutter_actor_queue_relayout (child->priv->parent);
11424     }
11425
11426   if (emit_actor_added)
11427     g_signal_emit_by_name (self, "actor-added", child);
11428
11429   if (notify_first_last)
11430     {
11431       if (old_first_child != self->priv->first_child)
11432         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11433
11434       if (old_last_child != self->priv->last_child)
11435         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11436     }
11437
11438   g_object_thaw_notify (G_OBJECT (self));
11439 }
11440
11441 /**
11442  * clutter_actor_add_child:
11443  * @self: a #ClutterActor
11444  * @child: a #ClutterActor
11445  *
11446  * Adds @child to the children of @self.
11447  *
11448  * This function will acquire a reference on @child that will only
11449  * be released when calling clutter_actor_remove_child().
11450  *
11451  * This function will take into consideration the #ClutterActor:depth
11452  * of @child, and will keep the list of children sorted.
11453  *
11454  * This function will emit the #ClutterContainer::actor-added signal
11455  * on @self.
11456  *
11457  * Since: 1.10
11458  */
11459 void
11460 clutter_actor_add_child (ClutterActor *self,
11461                          ClutterActor *child)
11462 {
11463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11464   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11465   g_return_if_fail (self != child);
11466   g_return_if_fail (child->priv->parent == NULL);
11467
11468   clutter_actor_add_child_internal (self, child,
11469                                     ADD_CHILD_DEFAULT_FLAGS,
11470                                     insert_child_at_depth,
11471                                     NULL);
11472 }
11473
11474 /**
11475  * clutter_actor_insert_child_at_index:
11476  * @self: a #ClutterActor
11477  * @child: a #ClutterActor
11478  * @index_: the index
11479  *
11480  * Inserts @child into the list of children of @self, using the
11481  * given @index_. If @index_ is greater than the number of children
11482  * in @self, or is less than 0, then the new child is added at the end.
11483  *
11484  * This function will acquire a reference on @child that will only
11485  * be released when calling clutter_actor_remove_child().
11486  *
11487  * This function will not take into consideration the #ClutterActor:depth
11488  * of @child.
11489  *
11490  * This function will emit the #ClutterContainer::actor-added signal
11491  * on @self.
11492  *
11493  * Since: 1.10
11494  */
11495 void
11496 clutter_actor_insert_child_at_index (ClutterActor *self,
11497                                      ClutterActor *child,
11498                                      gint          index_)
11499 {
11500   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11501   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11502   g_return_if_fail (self != child);
11503   g_return_if_fail (child->priv->parent == NULL);
11504
11505   clutter_actor_add_child_internal (self, child,
11506                                     ADD_CHILD_DEFAULT_FLAGS,
11507                                     insert_child_at_index,
11508                                     GINT_TO_POINTER (index_));
11509 }
11510
11511 /**
11512  * clutter_actor_insert_child_above:
11513  * @self: a #ClutterActor
11514  * @child: a #ClutterActor
11515  * @sibling: (allow-none): a child of @self, or %NULL
11516  *
11517  * Inserts @child into the list of children of @self, above another
11518  * child of @self or, if @sibling is %NULL, above all the children
11519  * of @self.
11520  *
11521  * This function will acquire a reference on @child that will only
11522  * be released when calling clutter_actor_remove_child().
11523  *
11524  * This function will not take into consideration the #ClutterActor:depth
11525  * of @child.
11526  *
11527  * This function will emit the #ClutterContainer::actor-added signal
11528  * on @self.
11529  *
11530  * Since: 1.10
11531  */
11532 void
11533 clutter_actor_insert_child_above (ClutterActor *self,
11534                                   ClutterActor *child,
11535                                   ClutterActor *sibling)
11536 {
11537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11538   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11539   g_return_if_fail (self != child);
11540   g_return_if_fail (child != sibling);
11541   g_return_if_fail (child->priv->parent == NULL);
11542   g_return_if_fail (sibling == NULL ||
11543                     (CLUTTER_IS_ACTOR (sibling) &&
11544                      sibling->priv->parent == self));
11545
11546   clutter_actor_add_child_internal (self, child,
11547                                     ADD_CHILD_DEFAULT_FLAGS,
11548                                     insert_child_above,
11549                                     sibling);
11550 }
11551
11552 /**
11553  * clutter_actor_insert_child_below:
11554  * @self: a #ClutterActor
11555  * @child: a #ClutterActor
11556  * @sibling: (allow-none): a child of @self, or %NULL
11557  *
11558  * Inserts @child into the list of children of @self, below another
11559  * child of @self or, if @sibling is %NULL, below all the children
11560  * of @self.
11561  *
11562  * This function will acquire a reference on @child that will only
11563  * be released when calling clutter_actor_remove_child().
11564  *
11565  * This function will not take into consideration the #ClutterActor:depth
11566  * of @child.
11567  *
11568  * This function will emit the #ClutterContainer::actor-added signal
11569  * on @self.
11570  *
11571  * Since: 1.10
11572  */
11573 void
11574 clutter_actor_insert_child_below (ClutterActor *self,
11575                                   ClutterActor *child,
11576                                   ClutterActor *sibling)
11577 {
11578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11579   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11580   g_return_if_fail (self != child);
11581   g_return_if_fail (child != sibling);
11582   g_return_if_fail (child->priv->parent == NULL);
11583   g_return_if_fail (sibling == NULL ||
11584                     (CLUTTER_IS_ACTOR (sibling) &&
11585                      sibling->priv->parent == self));
11586
11587   clutter_actor_add_child_internal (self, child,
11588                                     ADD_CHILD_DEFAULT_FLAGS,
11589                                     insert_child_below,
11590                                     sibling);
11591 }
11592
11593 /**
11594  * clutter_actor_set_parent:
11595  * @self: A #ClutterActor
11596  * @parent: A new #ClutterActor parent
11597  *
11598  * Sets the parent of @self to @parent.
11599  *
11600  * This function will result in @parent acquiring a reference on @self,
11601  * eventually by sinking its floating reference first. The reference
11602  * will be released by clutter_actor_unparent().
11603  *
11604  * This function should only be called by legacy #ClutterActor<!-- -->s
11605  * implementing the #ClutterContainer interface.
11606  *
11607  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11608  */
11609 void
11610 clutter_actor_set_parent (ClutterActor *self,
11611                           ClutterActor *parent)
11612 {
11613   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11614   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11615   g_return_if_fail (self != parent);
11616   g_return_if_fail (self->priv->parent == NULL);
11617
11618   /* as this function will be called inside ClutterContainer::add
11619    * implementations or when building up a composite actor, we have
11620    * to preserve the old behaviour, and not create child meta or
11621    * emit the ::actor-added signal, to avoid recursion or double
11622    * emissions
11623    */
11624   clutter_actor_add_child_internal (parent, self,
11625                                     ADD_CHILD_LEGACY_FLAGS,
11626                                     insert_child_at_depth,
11627                                     NULL);
11628 }
11629
11630 /**
11631  * clutter_actor_get_parent:
11632  * @self: A #ClutterActor
11633  *
11634  * Retrieves the parent of @self.
11635  *
11636  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11637  *  if no parent is set
11638  */
11639 ClutterActor *
11640 clutter_actor_get_parent (ClutterActor *self)
11641 {
11642   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11643
11644   return self->priv->parent;
11645 }
11646
11647 /**
11648  * clutter_actor_get_paint_visibility:
11649  * @self: A #ClutterActor
11650  *
11651  * Retrieves the 'paint' visibility of an actor recursively checking for non
11652  * visible parents.
11653  *
11654  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11655  *
11656  * Return Value: %TRUE if the actor is visibile and will be painted.
11657  *
11658  * Since: 0.8.4
11659  */
11660 gboolean
11661 clutter_actor_get_paint_visibility (ClutterActor *actor)
11662 {
11663   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11664
11665   return CLUTTER_ACTOR_IS_MAPPED (actor);
11666 }
11667
11668 /**
11669  * clutter_actor_remove_child:
11670  * @self: a #ClutterActor
11671  * @child: a #ClutterActor
11672  *
11673  * Removes @child from the children of @self.
11674  *
11675  * This function will release the reference added by
11676  * clutter_actor_add_child(), so if you want to keep using @child
11677  * you will have to acquire a referenced on it before calling this
11678  * function.
11679  *
11680  * This function will emit the #ClutterContainer::actor-removed
11681  * signal on @self.
11682  *
11683  * Since: 1.10
11684  */
11685 void
11686 clutter_actor_remove_child (ClutterActor *self,
11687                             ClutterActor *child)
11688 {
11689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11690   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11691   g_return_if_fail (self != child);
11692   g_return_if_fail (child->priv->parent != NULL);
11693   g_return_if_fail (child->priv->parent == self);
11694
11695   clutter_actor_remove_child_internal (self, child,
11696                                        REMOVE_CHILD_DEFAULT_FLAGS);
11697 }
11698
11699 /**
11700  * clutter_actor_remove_all_children:
11701  * @self: a #ClutterActor
11702  *
11703  * Removes all children of @self.
11704  *
11705  * This function releases the reference added by inserting a child actor
11706  * in the list of children of @self.
11707  *
11708  * If the reference count of a child drops to zero, the child will be
11709  * destroyed. If you want to ensure the destruction of all the children
11710  * of @self, use clutter_actor_destroy_all_children().
11711  *
11712  * Since: 1.10
11713  */
11714 void
11715 clutter_actor_remove_all_children (ClutterActor *self)
11716 {
11717   ClutterActorIter iter;
11718
11719   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11720
11721   if (self->priv->n_children == 0)
11722     return;
11723
11724   g_object_freeze_notify (G_OBJECT (self));
11725
11726   clutter_actor_iter_init (&iter, self);
11727   while (clutter_actor_iter_next (&iter, NULL))
11728     clutter_actor_iter_remove (&iter);
11729
11730   g_object_thaw_notify (G_OBJECT (self));
11731
11732   /* sanity check */
11733   g_assert (self->priv->first_child == NULL);
11734   g_assert (self->priv->last_child == NULL);
11735   g_assert (self->priv->n_children == 0);
11736 }
11737
11738 /**
11739  * clutter_actor_destroy_all_children:
11740  * @self: a #ClutterActor
11741  *
11742  * Destroys all children of @self.
11743  *
11744  * This function releases the reference added by inserting a child
11745  * actor in the list of children of @self, and ensures that the
11746  * #ClutterActor::destroy signal is emitted on each child of the
11747  * actor.
11748  *
11749  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11750  * when its reference count drops to 0; the default handler of the
11751  * #ClutterActor::destroy signal will destroy all the children of an
11752  * actor. This function ensures that all children are destroyed, instead
11753  * of just removed from @self, unlike clutter_actor_remove_all_children()
11754  * which will merely release the reference and remove each child.
11755  *
11756  * Unless you acquired an additional reference on each child of @self
11757  * prior to calling clutter_actor_remove_all_children() and want to reuse
11758  * the actors, you should use clutter_actor_destroy_all_children() in
11759  * order to make sure that children are destroyed and signal handlers
11760  * are disconnected even in cases where circular references prevent this
11761  * from automatically happening through reference counting alone.
11762  *
11763  * Since: 1.10
11764  */
11765 void
11766 clutter_actor_destroy_all_children (ClutterActor *self)
11767 {
11768   ClutterActorIter iter;
11769
11770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11771
11772   if (self->priv->n_children == 0)
11773     return;
11774
11775   g_object_freeze_notify (G_OBJECT (self));
11776
11777   clutter_actor_iter_init (&iter, self);
11778   while (clutter_actor_iter_next (&iter, NULL))
11779     clutter_actor_iter_destroy (&iter);
11780
11781   g_object_thaw_notify (G_OBJECT (self));
11782
11783   /* sanity check */
11784   g_assert (self->priv->first_child == NULL);
11785   g_assert (self->priv->last_child == NULL);
11786   g_assert (self->priv->n_children == 0);
11787 }
11788
11789 typedef struct _InsertBetweenData {
11790   ClutterActor *prev_sibling;
11791   ClutterActor *next_sibling;
11792 } InsertBetweenData;
11793
11794 static void
11795 insert_child_between (ClutterActor *self,
11796                       ClutterActor *child,
11797                       gpointer      data_)
11798 {
11799   InsertBetweenData *data = data_;
11800   ClutterActor *prev_sibling = data->prev_sibling;
11801   ClutterActor *next_sibling = data->next_sibling;
11802
11803   child->priv->parent = self;
11804   child->priv->prev_sibling = prev_sibling;
11805   child->priv->next_sibling = next_sibling;
11806
11807   if (prev_sibling != NULL)
11808     prev_sibling->priv->next_sibling = child;
11809
11810   if (next_sibling != NULL)
11811     next_sibling->priv->prev_sibling = child;
11812
11813   if (child->priv->prev_sibling == NULL)
11814     self->priv->first_child = child;
11815
11816   if (child->priv->next_sibling == NULL)
11817     self->priv->last_child = child;
11818 }
11819
11820 /**
11821  * clutter_actor_replace_child:
11822  * @self: a #ClutterActor
11823  * @old_child: the child of @self to replace
11824  * @new_child: the #ClutterActor to replace @old_child
11825  *
11826  * Replaces @old_child with @new_child in the list of children of @self.
11827  *
11828  * Since: 1.10
11829  */
11830 void
11831 clutter_actor_replace_child (ClutterActor *self,
11832                              ClutterActor *old_child,
11833                              ClutterActor *new_child)
11834 {
11835   ClutterActor *prev_sibling, *next_sibling;
11836   InsertBetweenData clos;
11837
11838   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11839   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11840   g_return_if_fail (old_child->priv->parent == self);
11841   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11842   g_return_if_fail (old_child != new_child);
11843   g_return_if_fail (new_child != self);
11844   g_return_if_fail (new_child->priv->parent == NULL);
11845
11846   prev_sibling = old_child->priv->prev_sibling;
11847   next_sibling = old_child->priv->next_sibling;
11848   clutter_actor_remove_child_internal (self, old_child,
11849                                        REMOVE_CHILD_DEFAULT_FLAGS);
11850
11851   clos.prev_sibling = prev_sibling;
11852   clos.next_sibling = next_sibling;
11853   clutter_actor_add_child_internal (self, new_child,
11854                                     ADD_CHILD_DEFAULT_FLAGS,
11855                                     insert_child_between,
11856                                     &clos);
11857 }
11858
11859 /**
11860  * clutter_actor_unparent:
11861  * @self: a #ClutterActor
11862  *
11863  * Removes the parent of @self.
11864  *
11865  * This will cause the parent of @self to release the reference
11866  * acquired when calling clutter_actor_set_parent(), so if you
11867  * want to keep @self you will have to acquire a reference of
11868  * your own, through g_object_ref().
11869  *
11870  * This function should only be called by legacy #ClutterActor<!-- -->s
11871  * implementing the #ClutterContainer interface.
11872  *
11873  * Since: 0.1.1
11874  *
11875  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11876  */
11877 void
11878 clutter_actor_unparent (ClutterActor *self)
11879 {
11880   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11881
11882   if (self->priv->parent == NULL)
11883     return;
11884
11885   clutter_actor_remove_child_internal (self->priv->parent, self,
11886                                        REMOVE_CHILD_LEGACY_FLAGS);
11887 }
11888
11889 /**
11890  * clutter_actor_reparent:
11891  * @self: a #ClutterActor
11892  * @new_parent: the new #ClutterActor parent
11893  *
11894  * Resets the parent actor of @self.
11895  *
11896  * This function is logically equivalent to calling clutter_actor_unparent()
11897  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11898  * ensures the child is not finalized when unparented, and emits the
11899  * #ClutterActor::parent-set signal only once.
11900  *
11901  * In reality, calling this function is less useful than it sounds, as some
11902  * application code may rely on changes in the intermediate state between
11903  * removal and addition of the actor from its old parent to the @new_parent.
11904  * Thus, it is strongly encouraged to avoid using this function in application
11905  * code.
11906  *
11907  * Since: 0.2
11908  *
11909  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11910  *   clutter_actor_add_child() instead; remember to take a reference on
11911  *   the actor being removed before calling clutter_actor_remove_child()
11912  *   to avoid the reference count dropping to zero and the actor being
11913  *   destroyed.
11914  */
11915 void
11916 clutter_actor_reparent (ClutterActor *self,
11917                         ClutterActor *new_parent)
11918 {
11919   ClutterActorPrivate *priv;
11920
11921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11922   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11923   g_return_if_fail (self != new_parent);
11924
11925   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11926     {
11927       g_warning ("Cannot set a parent on a toplevel actor");
11928       return;
11929     }
11930
11931   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11932     {
11933       g_warning ("Cannot set a parent currently being destroyed");
11934       return;
11935     }
11936
11937   priv = self->priv;
11938
11939   if (priv->parent != new_parent)
11940     {
11941       ClutterActor *old_parent;
11942
11943       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11944
11945       old_parent = priv->parent;
11946
11947       g_object_ref (self);
11948
11949       if (old_parent != NULL)
11950         {
11951          /* go through the Container implementation if this is a regular
11952           * child and not an internal one
11953           */
11954          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11955            {
11956              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11957
11958              /* this will have to call unparent() */
11959              clutter_container_remove_actor (parent, self);
11960            }
11961          else
11962            clutter_actor_remove_child_internal (old_parent, self,
11963                                                 REMOVE_CHILD_LEGACY_FLAGS);
11964         }
11965
11966       /* Note, will call set_parent() */
11967       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11968         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11969       else
11970         clutter_actor_add_child_internal (new_parent, self,
11971                                           ADD_CHILD_LEGACY_FLAGS,
11972                                           insert_child_at_depth,
11973                                           NULL);
11974
11975       /* we emit the ::parent-set signal once */
11976       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11977
11978       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11979
11980       /* the IN_REPARENT flag suspends state updates */
11981       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11982
11983       g_object_unref (self);
11984    }
11985 }
11986
11987 /**
11988  * clutter_actor_contains:
11989  * @self: A #ClutterActor
11990  * @descendant: A #ClutterActor, possibly contained in @self
11991  *
11992  * Determines if @descendant is contained inside @self (either as an
11993  * immediate child, or as a deeper descendant). If @self and
11994  * @descendant point to the same actor then it will also return %TRUE.
11995  *
11996  * Return value: whether @descendent is contained within @self
11997  *
11998  * Since: 1.4
11999  */
12000 gboolean
12001 clutter_actor_contains (ClutterActor *self,
12002                         ClutterActor *descendant)
12003 {
12004   ClutterActor *actor;
12005
12006   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12007   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12008
12009   for (actor = descendant; actor; actor = actor->priv->parent)
12010     if (actor == self)
12011       return TRUE;
12012
12013   return FALSE;
12014 }
12015
12016 /**
12017  * clutter_actor_set_child_above_sibling:
12018  * @self: a #ClutterActor
12019  * @child: a #ClutterActor child of @self
12020  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12021  *
12022  * Sets @child to be above @sibling in the list of children of @self.
12023  *
12024  * If @sibling is %NULL, @child will be the new last child of @self.
12025  *
12026  * This function is logically equivalent to removing @child and using
12027  * clutter_actor_insert_child_above(), but it will not emit signals
12028  * or change state on @child.
12029  *
12030  * Since: 1.10
12031  */
12032 void
12033 clutter_actor_set_child_above_sibling (ClutterActor *self,
12034                                        ClutterActor *child,
12035                                        ClutterActor *sibling)
12036 {
12037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12038   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12039   g_return_if_fail (child->priv->parent == self);
12040   g_return_if_fail (child != sibling);
12041   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12042
12043   if (sibling != NULL)
12044     g_return_if_fail (sibling->priv->parent == self);
12045
12046   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12047       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12048       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12049     return;
12050
12051   /* we don't want to change the state of child, or emit signals, or
12052    * regenerate ChildMeta instances here, but we still want to follow
12053    * the correct sequence of steps encoded in remove_child() and
12054    * add_child(), so that correctness is ensured, and we only go
12055    * through one known code path.
12056    */
12057   g_object_ref (child);
12058   clutter_actor_remove_child_internal (self, child, 0);
12059   clutter_actor_add_child_internal (self, child,
12060                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12061                                     insert_child_above,
12062                                     sibling);
12063
12064   clutter_actor_queue_relayout (self);
12065 }
12066
12067 /**
12068  * clutter_actor_set_child_below_sibling:
12069  * @self: a #ClutterActor
12070  * @child: a #ClutterActor child of @self
12071  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12072  *
12073  * Sets @child to be below @sibling in the list of children of @self.
12074  *
12075  * If @sibling is %NULL, @child will be the new first child of @self.
12076  *
12077  * This function is logically equivalent to removing @self and using
12078  * clutter_actor_insert_child_below(), but it will not emit signals
12079  * or change state on @child.
12080  *
12081  * Since: 1.10
12082  */
12083 void
12084 clutter_actor_set_child_below_sibling (ClutterActor *self,
12085                                        ClutterActor *child,
12086                                        ClutterActor *sibling)
12087 {
12088   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12089   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12090   g_return_if_fail (child->priv->parent == self);
12091   g_return_if_fail (child != sibling);
12092   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12093
12094   if (sibling != NULL)
12095     g_return_if_fail (sibling->priv->parent == self);
12096
12097   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12098       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12099       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12100     return;
12101
12102   /* see the comment in set_child_above_sibling() */
12103   g_object_ref (child);
12104   clutter_actor_remove_child_internal (self, child, 0);
12105   clutter_actor_add_child_internal (self, child,
12106                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12107                                     insert_child_below,
12108                                     sibling);
12109
12110   clutter_actor_queue_relayout (self);
12111 }
12112
12113 /**
12114  * clutter_actor_set_child_at_index:
12115  * @self: a #ClutterActor
12116  * @child: a #ClutterActor child of @self
12117  * @index_: the new index for @child
12118  *
12119  * Changes the index of @child in the list of children of @self.
12120  *
12121  * This function is logically equivalent to removing @child and
12122  * calling clutter_actor_insert_child_at_index(), but it will not
12123  * emit signals or change state on @child.
12124  *
12125  * Since: 1.10
12126  */
12127 void
12128 clutter_actor_set_child_at_index (ClutterActor *self,
12129                                   ClutterActor *child,
12130                                   gint          index_)
12131 {
12132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12133   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12134   g_return_if_fail (child->priv->parent == self);
12135   g_return_if_fail (index_ <= self->priv->n_children);
12136
12137   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12138       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12139     return;
12140
12141   g_object_ref (child);
12142   clutter_actor_remove_child_internal (self, child, 0);
12143   clutter_actor_add_child_internal (self, child,
12144                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12145                                     insert_child_at_index,
12146                                     GINT_TO_POINTER (index_));
12147
12148   clutter_actor_queue_relayout (self);
12149 }
12150
12151 /**
12152  * clutter_actor_raise:
12153  * @self: A #ClutterActor
12154  * @below: (allow-none): A #ClutterActor to raise above.
12155  *
12156  * Puts @self above @below.
12157  *
12158  * Both actors must have the same parent, and the parent must implement
12159  * the #ClutterContainer interface
12160  *
12161  * This function calls clutter_container_raise_child() internally.
12162  *
12163  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12164  */
12165 void
12166 clutter_actor_raise (ClutterActor *self,
12167                      ClutterActor *below)
12168 {
12169   ClutterActor *parent;
12170
12171   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12172
12173   parent = clutter_actor_get_parent (self);
12174   if (parent == NULL)
12175     {
12176       g_warning ("%s: Actor '%s' is not inside a container",
12177                  G_STRFUNC,
12178                  _clutter_actor_get_debug_name (self));
12179       return;
12180     }
12181
12182   if (below != NULL)
12183     {
12184       if (parent != clutter_actor_get_parent (below))
12185         {
12186           g_warning ("%s Actor '%s' is not in the same container as "
12187                      "actor '%s'",
12188                      G_STRFUNC,
12189                      _clutter_actor_get_debug_name (self),
12190                      _clutter_actor_get_debug_name (below));
12191           return;
12192         }
12193     }
12194
12195   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12196 }
12197
12198 /**
12199  * clutter_actor_lower:
12200  * @self: A #ClutterActor
12201  * @above: (allow-none): A #ClutterActor to lower below
12202  *
12203  * Puts @self below @above.
12204  *
12205  * Both actors must have the same parent, and the parent must implement
12206  * the #ClutterContainer interface.
12207  *
12208  * This function calls clutter_container_lower_child() internally.
12209  *
12210  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12211  */
12212 void
12213 clutter_actor_lower (ClutterActor *self,
12214                      ClutterActor *above)
12215 {
12216   ClutterActor *parent;
12217
12218   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12219
12220   parent = clutter_actor_get_parent (self);
12221   if (parent == NULL)
12222     {
12223       g_warning ("%s: Actor of type %s is not inside a container",
12224                  G_STRFUNC,
12225                  _clutter_actor_get_debug_name (self));
12226       return;
12227     }
12228
12229   if (above)
12230     {
12231       if (parent != clutter_actor_get_parent (above))
12232         {
12233           g_warning ("%s: Actor '%s' is not in the same container as "
12234                      "actor '%s'",
12235                      G_STRFUNC,
12236                      _clutter_actor_get_debug_name (self),
12237                      _clutter_actor_get_debug_name (above));
12238           return;
12239         }
12240     }
12241
12242   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12243 }
12244
12245 /**
12246  * clutter_actor_raise_top:
12247  * @self: A #ClutterActor
12248  *
12249  * Raises @self to the top.
12250  *
12251  * This function calls clutter_actor_raise() internally.
12252  *
12253  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12254  *   a %NULL sibling, instead.
12255  */
12256 void
12257 clutter_actor_raise_top (ClutterActor *self)
12258 {
12259   clutter_actor_raise (self, NULL);
12260 }
12261
12262 /**
12263  * clutter_actor_lower_bottom:
12264  * @self: A #ClutterActor
12265  *
12266  * Lowers @self to the bottom.
12267  *
12268  * This function calls clutter_actor_lower() internally.
12269  *
12270  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12271  *   a %NULL sibling, instead.
12272  */
12273 void
12274 clutter_actor_lower_bottom (ClutterActor *self)
12275 {
12276   clutter_actor_lower (self, NULL);
12277 }
12278
12279 /*
12280  * Event handling
12281  */
12282
12283 /**
12284  * clutter_actor_event:
12285  * @actor: a #ClutterActor
12286  * @event: a #ClutterEvent
12287  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12288  *
12289  * This function is used to emit an event on the main stage.
12290  * You should rarely need to use this function, except for
12291  * synthetising events.
12292  *
12293  * Return value: the return value from the signal emission: %TRUE
12294  *   if the actor handled the event, or %FALSE if the event was
12295  *   not handled
12296  *
12297  * Since: 0.6
12298  */
12299 gboolean
12300 clutter_actor_event (ClutterActor *actor,
12301                      ClutterEvent *event,
12302                      gboolean      capture)
12303 {
12304   gboolean retval = FALSE;
12305   gint signal_num = -1;
12306
12307   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12308   g_return_val_if_fail (event != NULL, FALSE);
12309
12310   g_object_ref (actor);
12311
12312   if (capture)
12313     {
12314       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12315                      event,
12316                      &retval);
12317       goto out;
12318     }
12319
12320   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12321
12322   if (!retval)
12323     {
12324       switch (event->type)
12325         {
12326         case CLUTTER_NOTHING:
12327           break;
12328         case CLUTTER_BUTTON_PRESS:
12329           signal_num = BUTTON_PRESS_EVENT;
12330           break;
12331         case CLUTTER_BUTTON_RELEASE:
12332           signal_num = BUTTON_RELEASE_EVENT;
12333           break;
12334         case CLUTTER_SCROLL:
12335           signal_num = SCROLL_EVENT;
12336           break;
12337         case CLUTTER_KEY_PRESS:
12338           signal_num = KEY_PRESS_EVENT;
12339           break;
12340         case CLUTTER_KEY_RELEASE:
12341           signal_num = KEY_RELEASE_EVENT;
12342           break;
12343         case CLUTTER_MOTION:
12344           signal_num = MOTION_EVENT;
12345           break;
12346         case CLUTTER_ENTER:
12347           signal_num = ENTER_EVENT;
12348           break;
12349         case CLUTTER_LEAVE:
12350           signal_num = LEAVE_EVENT;
12351           break;
12352         case CLUTTER_DELETE:
12353         case CLUTTER_DESTROY_NOTIFY:
12354         case CLUTTER_CLIENT_MESSAGE:
12355         default:
12356           signal_num = -1;
12357           break;
12358         }
12359
12360       if (signal_num != -1)
12361         g_signal_emit (actor, actor_signals[signal_num], 0,
12362                        event, &retval);
12363     }
12364
12365 out:
12366   g_object_unref (actor);
12367
12368   return retval;
12369 }
12370
12371 /**
12372  * clutter_actor_set_reactive:
12373  * @actor: a #ClutterActor
12374  * @reactive: whether the actor should be reactive to events
12375  *
12376  * Sets @actor as reactive. Reactive actors will receive events.
12377  *
12378  * Since: 0.6
12379  */
12380 void
12381 clutter_actor_set_reactive (ClutterActor *actor,
12382                             gboolean      reactive)
12383 {
12384   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12385
12386   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12387     return;
12388
12389   if (reactive)
12390     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12391   else
12392     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12393
12394   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12395 }
12396
12397 /**
12398  * clutter_actor_get_reactive:
12399  * @actor: a #ClutterActor
12400  *
12401  * Checks whether @actor is marked as reactive.
12402  *
12403  * Return value: %TRUE if the actor is reactive
12404  *
12405  * Since: 0.6
12406  */
12407 gboolean
12408 clutter_actor_get_reactive (ClutterActor *actor)
12409 {
12410   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12411
12412   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12413 }
12414
12415 /**
12416  * clutter_actor_get_anchor_point:
12417  * @self: a #ClutterActor
12418  * @anchor_x: (out): return location for the X coordinate of the anchor point
12419  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12420  *
12421  * Gets the current anchor point of the @actor in pixels.
12422  *
12423  * Since: 0.6
12424  */
12425 void
12426 clutter_actor_get_anchor_point (ClutterActor *self,
12427                                 gfloat       *anchor_x,
12428                                 gfloat       *anchor_y)
12429 {
12430   const ClutterTransformInfo *info;
12431
12432   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12433
12434   info = _clutter_actor_get_transform_info_or_defaults (self);
12435   clutter_anchor_coord_get_units (self, &info->anchor,
12436                                   anchor_x,
12437                                   anchor_y,
12438                                   NULL);
12439 }
12440
12441 /**
12442  * clutter_actor_set_anchor_point:
12443  * @self: a #ClutterActor
12444  * @anchor_x: X coordinate of the anchor point
12445  * @anchor_y: Y coordinate of the anchor point
12446  *
12447  * Sets an anchor point for @self. The anchor point is a point in the
12448  * coordinate space of an actor to which the actor position within its
12449  * parent is relative; the default is (0, 0), i.e. the top-left corner
12450  * of the actor.
12451  *
12452  * Since: 0.6
12453  */
12454 void
12455 clutter_actor_set_anchor_point (ClutterActor *self,
12456                                 gfloat        anchor_x,
12457                                 gfloat        anchor_y)
12458 {
12459   ClutterTransformInfo *info;
12460   ClutterActorPrivate *priv;
12461   gboolean changed = FALSE;
12462   gfloat old_anchor_x, old_anchor_y;
12463   GObject *obj;
12464
12465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12466
12467   obj = G_OBJECT (self);
12468   priv = self->priv;
12469   info = _clutter_actor_get_transform_info (self);
12470
12471   g_object_freeze_notify (obj);
12472
12473   clutter_anchor_coord_get_units (self, &info->anchor,
12474                                   &old_anchor_x,
12475                                   &old_anchor_y,
12476                                   NULL);
12477
12478   if (info->anchor.is_fractional)
12479     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12480
12481   if (old_anchor_x != anchor_x)
12482     {
12483       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12484       changed = TRUE;
12485     }
12486
12487   if (old_anchor_y != anchor_y)
12488     {
12489       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12490       changed = TRUE;
12491     }
12492
12493   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12494
12495   if (changed)
12496     {
12497       priv->transform_valid = FALSE;
12498       clutter_actor_queue_redraw (self);
12499     }
12500
12501   g_object_thaw_notify (obj);
12502 }
12503
12504 /**
12505  * clutter_actor_get_anchor_point_gravity:
12506  * @self: a #ClutterActor
12507  *
12508  * Retrieves the anchor position expressed as a #ClutterGravity. If
12509  * the anchor point was specified using pixels or units this will
12510  * return %CLUTTER_GRAVITY_NONE.
12511  *
12512  * Return value: the #ClutterGravity used by the anchor point
12513  *
12514  * Since: 1.0
12515  */
12516 ClutterGravity
12517 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12518 {
12519   const ClutterTransformInfo *info;
12520
12521   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12522
12523   info = _clutter_actor_get_transform_info_or_defaults (self);
12524
12525   return clutter_anchor_coord_get_gravity (&info->anchor);
12526 }
12527
12528 /**
12529  * clutter_actor_move_anchor_point:
12530  * @self: a #ClutterActor
12531  * @anchor_x: X coordinate of the anchor point
12532  * @anchor_y: Y coordinate of the anchor point
12533  *
12534  * Sets an anchor point for the actor, and adjusts the actor postion so that
12535  * the relative position of the actor toward its parent remains the same.
12536  *
12537  * Since: 0.6
12538  */
12539 void
12540 clutter_actor_move_anchor_point (ClutterActor *self,
12541                                  gfloat        anchor_x,
12542                                  gfloat        anchor_y)
12543 {
12544   gfloat old_anchor_x, old_anchor_y;
12545   const ClutterTransformInfo *info;
12546
12547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12548
12549   info = _clutter_actor_get_transform_info (self);
12550   clutter_anchor_coord_get_units (self, &info->anchor,
12551                                   &old_anchor_x,
12552                                   &old_anchor_y,
12553                                   NULL);
12554
12555   g_object_freeze_notify (G_OBJECT (self));
12556
12557   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12558
12559   if (self->priv->position_set)
12560     clutter_actor_move_by (self,
12561                            anchor_x - old_anchor_x,
12562                            anchor_y - old_anchor_y);
12563
12564   g_object_thaw_notify (G_OBJECT (self));
12565 }
12566
12567 /**
12568  * clutter_actor_move_anchor_point_from_gravity:
12569  * @self: a #ClutterActor
12570  * @gravity: #ClutterGravity.
12571  *
12572  * Sets an anchor point on the actor based on the given gravity, adjusting the
12573  * actor postion so that its relative position within its parent remains
12574  * unchanged.
12575  *
12576  * Since version 1.0 the anchor point will be stored as a gravity so
12577  * that if the actor changes size then the anchor point will move. For
12578  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12579  * and later double the size of the actor, the anchor point will move
12580  * to the bottom right.
12581  *
12582  * Since: 0.6
12583  */
12584 void
12585 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12586                                               ClutterGravity  gravity)
12587 {
12588   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12589   const ClutterTransformInfo *info;
12590   ClutterActorPrivate *priv;
12591
12592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12593
12594   priv = self->priv;
12595   info = _clutter_actor_get_transform_info (self);
12596
12597   g_object_freeze_notify (G_OBJECT (self));
12598
12599   clutter_anchor_coord_get_units (self, &info->anchor,
12600                                   &old_anchor_x,
12601                                   &old_anchor_y,
12602                                   NULL);
12603   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12604   clutter_anchor_coord_get_units (self, &info->anchor,
12605                                   &new_anchor_x,
12606                                   &new_anchor_y,
12607                                   NULL);
12608
12609   if (priv->position_set)
12610     clutter_actor_move_by (self,
12611                            new_anchor_x - old_anchor_x,
12612                            new_anchor_y - old_anchor_y);
12613
12614   g_object_thaw_notify (G_OBJECT (self));
12615 }
12616
12617 /**
12618  * clutter_actor_set_anchor_point_from_gravity:
12619  * @self: a #ClutterActor
12620  * @gravity: #ClutterGravity.
12621  *
12622  * Sets an anchor point on the actor, based on the given gravity (this is a
12623  * convenience function wrapping clutter_actor_set_anchor_point()).
12624  *
12625  * Since version 1.0 the anchor point will be stored as a gravity so
12626  * that if the actor changes size then the anchor point will move. For
12627  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12628  * and later double the size of the actor, the anchor point will move
12629  * to the bottom right.
12630  *
12631  * Since: 0.6
12632  */
12633 void
12634 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12635                                              ClutterGravity  gravity)
12636 {
12637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12638
12639   if (gravity == CLUTTER_GRAVITY_NONE)
12640     clutter_actor_set_anchor_point (self, 0, 0);
12641   else
12642     {
12643       GObject *obj = G_OBJECT (self);
12644       ClutterTransformInfo *info;
12645
12646       g_object_freeze_notify (obj);
12647
12648       info = _clutter_actor_get_transform_info (self);
12649       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12650
12651       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12652       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12653       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12654
12655       self->priv->transform_valid = FALSE;
12656
12657       clutter_actor_queue_redraw (self);
12658
12659       g_object_thaw_notify (obj);
12660     }
12661 }
12662
12663 static void
12664 clutter_actor_store_content_box (ClutterActor *self,
12665                                  const ClutterActorBox *box)
12666 {
12667   if (box != NULL)
12668     {
12669       self->priv->content_box = *box;
12670       self->priv->content_box_valid = TRUE;
12671     }
12672   else
12673     self->priv->content_box_valid = FALSE;
12674
12675   clutter_actor_queue_redraw (self);
12676
12677   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12678 }
12679
12680 static void
12681 clutter_container_iface_init (ClutterContainerIface *iface)
12682 {
12683   /* we don't override anything, as ClutterContainer already has a default
12684    * implementation that we can use, and which calls into our own API.
12685    */
12686 }
12687
12688 typedef enum
12689 {
12690   PARSE_X,
12691   PARSE_Y,
12692   PARSE_WIDTH,
12693   PARSE_HEIGHT,
12694   PARSE_ANCHOR_X,
12695   PARSE_ANCHOR_Y
12696 } ParseDimension;
12697
12698 static gfloat
12699 parse_units (ClutterActor   *self,
12700              ParseDimension  dimension,
12701              JsonNode       *node)
12702 {
12703   GValue value = G_VALUE_INIT;
12704   gfloat retval = 0;
12705
12706   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12707     return 0;
12708
12709   json_node_get_value (node, &value);
12710
12711   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12712     {
12713       retval = (gfloat) g_value_get_int64 (&value);
12714     }
12715   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12716     {
12717       retval = g_value_get_double (&value);
12718     }
12719   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12720     {
12721       ClutterUnits units;
12722       gboolean res;
12723
12724       res = clutter_units_from_string (&units, g_value_get_string (&value));
12725       if (res)
12726         retval = clutter_units_to_pixels (&units);
12727       else
12728         {
12729           g_warning ("Invalid value '%s': integers, strings or floating point "
12730                      "values can be used for the x, y, width and height "
12731                      "properties. Valid modifiers for strings are 'px', 'mm', "
12732                      "'pt' and 'em'.",
12733                      g_value_get_string (&value));
12734           retval = 0;
12735         }
12736     }
12737   else
12738     {
12739       g_warning ("Invalid value of type '%s': integers, strings of floating "
12740                  "point values can be used for the x, y, width, height "
12741                  "anchor-x and anchor-y properties.",
12742                  g_type_name (G_VALUE_TYPE (&value)));
12743     }
12744
12745   g_value_unset (&value);
12746
12747   return retval;
12748 }
12749
12750 typedef struct {
12751   ClutterRotateAxis axis;
12752
12753   gdouble angle;
12754
12755   gfloat center_x;
12756   gfloat center_y;
12757   gfloat center_z;
12758 } RotationInfo;
12759
12760 static inline gboolean
12761 parse_rotation_array (ClutterActor *actor,
12762                       JsonArray    *array,
12763                       RotationInfo *info)
12764 {
12765   JsonNode *element;
12766
12767   if (json_array_get_length (array) != 2)
12768     return FALSE;
12769
12770   /* angle */
12771   element = json_array_get_element (array, 0);
12772   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12773     info->angle = json_node_get_double (element);
12774   else
12775     return FALSE;
12776
12777   /* center */
12778   element = json_array_get_element (array, 1);
12779   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12780     {
12781       JsonArray *center = json_node_get_array (element);
12782
12783       if (json_array_get_length (center) != 2)
12784         return FALSE;
12785
12786       switch (info->axis)
12787         {
12788         case CLUTTER_X_AXIS:
12789           info->center_y = parse_units (actor, PARSE_Y,
12790                                         json_array_get_element (center, 0));
12791           info->center_z = parse_units (actor, PARSE_Y,
12792                                         json_array_get_element (center, 1));
12793           return TRUE;
12794
12795         case CLUTTER_Y_AXIS:
12796           info->center_x = parse_units (actor, PARSE_X,
12797                                         json_array_get_element (center, 0));
12798           info->center_z = parse_units (actor, PARSE_X,
12799                                         json_array_get_element (center, 1));
12800           return TRUE;
12801
12802         case CLUTTER_Z_AXIS:
12803           info->center_x = parse_units (actor, PARSE_X,
12804                                         json_array_get_element (center, 0));
12805           info->center_y = parse_units (actor, PARSE_Y,
12806                                         json_array_get_element (center, 1));
12807           return TRUE;
12808         }
12809     }
12810
12811   return FALSE;
12812 }
12813
12814 static gboolean
12815 parse_rotation (ClutterActor *actor,
12816                 JsonNode     *node,
12817                 RotationInfo *info)
12818 {
12819   JsonArray *array;
12820   guint len, i;
12821   gboolean retval = FALSE;
12822
12823   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12824     {
12825       g_warning ("Invalid node of type '%s' found, expecting an array",
12826                  json_node_type_name (node));
12827       return FALSE;
12828     }
12829
12830   array = json_node_get_array (node);
12831   len = json_array_get_length (array);
12832
12833   for (i = 0; i < len; i++)
12834     {
12835       JsonNode *element = json_array_get_element (array, i);
12836       JsonObject *object;
12837       JsonNode *member;
12838
12839       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12840         {
12841           g_warning ("Invalid node of type '%s' found, expecting an object",
12842                      json_node_type_name (element));
12843           return FALSE;
12844         }
12845
12846       object = json_node_get_object (element);
12847
12848       if (json_object_has_member (object, "x-axis"))
12849         {
12850           member = json_object_get_member (object, "x-axis");
12851
12852           info->axis = CLUTTER_X_AXIS;
12853
12854           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12855             {
12856               info->angle = json_node_get_double (member);
12857               retval = TRUE;
12858             }
12859           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12860             retval = parse_rotation_array (actor,
12861                                            json_node_get_array (member),
12862                                            info);
12863           else
12864             retval = FALSE;
12865         }
12866       else if (json_object_has_member (object, "y-axis"))
12867         {
12868           member = json_object_get_member (object, "y-axis");
12869
12870           info->axis = CLUTTER_Y_AXIS;
12871
12872           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12873             {
12874               info->angle = json_node_get_double (member);
12875               retval = TRUE;
12876             }
12877           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12878             retval = parse_rotation_array (actor,
12879                                            json_node_get_array (member),
12880                                            info);
12881           else
12882             retval = FALSE;
12883         }
12884       else if (json_object_has_member (object, "z-axis"))
12885         {
12886           member = json_object_get_member (object, "z-axis");
12887
12888           info->axis = CLUTTER_Z_AXIS;
12889
12890           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12891             {
12892               info->angle = json_node_get_double (member);
12893               retval = TRUE;
12894             }
12895           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12896             retval = parse_rotation_array (actor,
12897                                            json_node_get_array (member),
12898                                            info);
12899           else
12900             retval = FALSE;
12901         }
12902     }
12903
12904   return retval;
12905 }
12906
12907 static GSList *
12908 parse_actor_metas (ClutterScript *script,
12909                    ClutterActor  *actor,
12910                    JsonNode      *node)
12911 {
12912   GList *elements, *l;
12913   GSList *retval = NULL;
12914
12915   if (!JSON_NODE_HOLDS_ARRAY (node))
12916     return NULL;
12917
12918   elements = json_array_get_elements (json_node_get_array (node));
12919
12920   for (l = elements; l != NULL; l = l->next)
12921     {
12922       JsonNode *element = l->data;
12923       const gchar *id_ = _clutter_script_get_id_from_node (element);
12924       GObject *meta;
12925
12926       if (id_ == NULL || *id_ == '\0')
12927         continue;
12928
12929       meta = clutter_script_get_object (script, id_);
12930       if (meta == NULL)
12931         continue;
12932
12933       retval = g_slist_prepend (retval, meta);
12934     }
12935
12936   g_list_free (elements);
12937
12938   return g_slist_reverse (retval);
12939 }
12940
12941 static GSList *
12942 parse_behaviours (ClutterScript *script,
12943                   ClutterActor  *actor,
12944                   JsonNode      *node)
12945 {
12946   GList *elements, *l;
12947   GSList *retval = NULL;
12948
12949   if (!JSON_NODE_HOLDS_ARRAY (node))
12950     return NULL;
12951
12952   elements = json_array_get_elements (json_node_get_array (node));
12953
12954   for (l = elements; l != NULL; l = l->next)
12955     {
12956       JsonNode *element = l->data;
12957       const gchar *id_ = _clutter_script_get_id_from_node (element);
12958       GObject *behaviour;
12959
12960       if (id_ == NULL || *id_ == '\0')
12961         continue;
12962
12963       behaviour = clutter_script_get_object (script, id_);
12964       if (behaviour == NULL)
12965         continue;
12966
12967       retval = g_slist_prepend (retval, behaviour);
12968     }
12969
12970   g_list_free (elements);
12971
12972   return g_slist_reverse (retval);
12973 }
12974
12975 static gboolean
12976 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12977                                  ClutterScript     *script,
12978                                  GValue            *value,
12979                                  const gchar       *name,
12980                                  JsonNode          *node)
12981 {
12982   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12983   gboolean retval = FALSE;
12984
12985   if ((name[0] == 'x' && name[1] == '\0') ||
12986       (name[0] == 'y' && name[1] == '\0') ||
12987       (strcmp (name, "width") == 0) ||
12988       (strcmp (name, "height") == 0) ||
12989       (strcmp (name, "anchor_x") == 0) ||
12990       (strcmp (name, "anchor_y") == 0))
12991     {
12992       ParseDimension dimension;
12993       gfloat units;
12994
12995       if (name[0] == 'x')
12996         dimension = PARSE_X;
12997       else if (name[0] == 'y')
12998         dimension = PARSE_Y;
12999       else if (name[0] == 'w')
13000         dimension = PARSE_WIDTH;
13001       else if (name[0] == 'h')
13002         dimension = PARSE_HEIGHT;
13003       else if (name[0] == 'a' && name[7] == 'x')
13004         dimension = PARSE_ANCHOR_X;
13005       else if (name[0] == 'a' && name[7] == 'y')
13006         dimension = PARSE_ANCHOR_Y;
13007       else
13008         return FALSE;
13009
13010       units = parse_units (actor, dimension, node);
13011
13012       /* convert back to pixels: all properties are pixel-based */
13013       g_value_init (value, G_TYPE_FLOAT);
13014       g_value_set_float (value, units);
13015
13016       retval = TRUE;
13017     }
13018   else if (strcmp (name, "rotation") == 0)
13019     {
13020       RotationInfo *info;
13021
13022       info = g_slice_new0 (RotationInfo);
13023       retval = parse_rotation (actor, node, info);
13024
13025       if (retval)
13026         {
13027           g_value_init (value, G_TYPE_POINTER);
13028           g_value_set_pointer (value, info);
13029         }
13030       else
13031         g_slice_free (RotationInfo, info);
13032     }
13033   else if (strcmp (name, "behaviours") == 0)
13034     {
13035       GSList *l;
13036
13037 #ifdef CLUTTER_ENABLE_DEBUG
13038       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13039         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13040                                      "and it should not be used in newly "
13041                                      "written ClutterScript definitions.");
13042 #endif
13043
13044       l = parse_behaviours (script, actor, node);
13045
13046       g_value_init (value, G_TYPE_POINTER);
13047       g_value_set_pointer (value, l);
13048
13049       retval = TRUE;
13050     }
13051   else if (strcmp (name, "actions") == 0 ||
13052            strcmp (name, "constraints") == 0 ||
13053            strcmp (name, "effects") == 0)
13054     {
13055       GSList *l;
13056
13057       l = parse_actor_metas (script, actor, node);
13058
13059       g_value_init (value, G_TYPE_POINTER);
13060       g_value_set_pointer (value, l);
13061
13062       retval = TRUE;
13063     }
13064
13065   return retval;
13066 }
13067
13068 static void
13069 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13070                                    ClutterScript     *script,
13071                                    const gchar       *name,
13072                                    const GValue      *value)
13073 {
13074   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13075
13076 #ifdef CLUTTER_ENABLE_DEBUG
13077   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13078     {
13079       gchar *tmp = g_strdup_value_contents (value);
13080
13081       CLUTTER_NOTE (SCRIPT,
13082                     "in ClutterActor::set_custom_property('%s') = %s",
13083                     name,
13084                     tmp);
13085
13086       g_free (tmp);
13087     }
13088 #endif /* CLUTTER_ENABLE_DEBUG */
13089
13090   if (strcmp (name, "rotation") == 0)
13091     {
13092       RotationInfo *info;
13093
13094       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13095         return;
13096
13097       info = g_value_get_pointer (value);
13098
13099       clutter_actor_set_rotation (actor,
13100                                   info->axis, info->angle,
13101                                   info->center_x,
13102                                   info->center_y,
13103                                   info->center_z);
13104
13105       g_slice_free (RotationInfo, info);
13106
13107       return;
13108     }
13109
13110   if (strcmp (name, "behaviours") == 0)
13111     {
13112       GSList *behaviours, *l;
13113
13114       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13115         return;
13116
13117       behaviours = g_value_get_pointer (value);
13118       for (l = behaviours; l != NULL; l = l->next)
13119         {
13120           ClutterBehaviour *behaviour = l->data;
13121
13122           clutter_behaviour_apply (behaviour, actor);
13123         }
13124
13125       g_slist_free (behaviours);
13126
13127       return;
13128     }
13129
13130   if (strcmp (name, "actions") == 0 ||
13131       strcmp (name, "constraints") == 0 ||
13132       strcmp (name, "effects") == 0)
13133     {
13134       GSList *metas, *l;
13135
13136       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13137         return;
13138
13139       metas = g_value_get_pointer (value);
13140       for (l = metas; l != NULL; l = l->next)
13141         {
13142           if (name[0] == 'a')
13143             clutter_actor_add_action (actor, l->data);
13144
13145           if (name[0] == 'c')
13146             clutter_actor_add_constraint (actor, l->data);
13147
13148           if (name[0] == 'e')
13149             clutter_actor_add_effect (actor, l->data);
13150         }
13151
13152       g_slist_free (metas);
13153
13154       return;
13155     }
13156
13157   g_object_set_property (G_OBJECT (scriptable), name, value);
13158 }
13159
13160 static void
13161 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13162 {
13163   iface->parse_custom_node = clutter_actor_parse_custom_node;
13164   iface->set_custom_property = clutter_actor_set_custom_property;
13165 }
13166
13167 static ClutterActorMeta *
13168 get_meta_from_animation_property (ClutterActor  *actor,
13169                                   const gchar   *name,
13170                                   gchar        **name_p)
13171 {
13172   ClutterActorPrivate *priv = actor->priv;
13173   ClutterActorMeta *meta = NULL;
13174   gchar **tokens;
13175
13176   /* if this is not a special property, fall through */
13177   if (name[0] != '@')
13178     return NULL;
13179
13180   /* detect the properties named using the following spec:
13181    *
13182    *   @<section>.<meta-name>.<property-name>
13183    *
13184    * where <section> can be one of the following:
13185    *
13186    *   - actions
13187    *   - constraints
13188    *   - effects
13189    *
13190    * and <meta-name> is the name set on a specific ActorMeta
13191    */
13192
13193   tokens = g_strsplit (name + 1, ".", -1);
13194   if (tokens == NULL || g_strv_length (tokens) != 3)
13195     {
13196       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13197                     name + 1);
13198       g_strfreev (tokens);
13199       return NULL;
13200     }
13201
13202   if (strcmp (tokens[0], "actions") == 0)
13203     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13204
13205   if (strcmp (tokens[0], "constraints") == 0)
13206     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13207
13208   if (strcmp (tokens[0], "effects") == 0)
13209     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13210
13211   if (name_p != NULL)
13212     *name_p = g_strdup (tokens[2]);
13213
13214   CLUTTER_NOTE (ANIMATION,
13215                 "Looking for property '%s' of object '%s' in section '%s'",
13216                 tokens[2],
13217                 tokens[1],
13218                 tokens[0]);
13219
13220   g_strfreev (tokens);
13221
13222   return meta;
13223 }
13224
13225 static GParamSpec *
13226 clutter_actor_find_property (ClutterAnimatable *animatable,
13227                              const gchar       *property_name)
13228 {
13229   ClutterActorMeta *meta = NULL;
13230   GObjectClass *klass = NULL;
13231   GParamSpec *pspec = NULL;
13232   gchar *p_name = NULL;
13233
13234   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13235                                            property_name,
13236                                            &p_name);
13237
13238   if (meta != NULL)
13239     {
13240       klass = G_OBJECT_GET_CLASS (meta);
13241
13242       pspec = g_object_class_find_property (klass, p_name);
13243     }
13244   else
13245     {
13246       klass = G_OBJECT_GET_CLASS (animatable);
13247
13248       pspec = g_object_class_find_property (klass, property_name);
13249     }
13250
13251   g_free (p_name);
13252
13253   return pspec;
13254 }
13255
13256 static void
13257 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13258                                  const gchar       *property_name,
13259                                  GValue            *initial)
13260 {
13261   ClutterActorMeta *meta = NULL;
13262   gchar *p_name = NULL;
13263
13264   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13265                                            property_name,
13266                                            &p_name);
13267
13268   if (meta != NULL)
13269     g_object_get_property (G_OBJECT (meta), p_name, initial);
13270   else
13271     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13272
13273   g_free (p_name);
13274 }
13275
13276 /*
13277  * clutter_actor_set_animatable_property:
13278  * @actor: a #ClutterActor
13279  * @prop_id: the paramspec id
13280  * @value: the value to set
13281  * @pspec: the paramspec
13282  *
13283  * Sets values of animatable properties.
13284  *
13285  * This is a variant of clutter_actor_set_property() that gets called
13286  * by the #ClutterAnimatable implementation of #ClutterActor for the
13287  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13288  * #GParamSpec.
13289  *
13290  * Unlike the implementation of #GObjectClass.set_property(), this
13291  * function will not update the interval if a transition involving an
13292  * animatable property is in progress - this avoids cycles with the
13293  * transition API calling the public API.
13294  */
13295 static void
13296 clutter_actor_set_animatable_property (ClutterActor *actor,
13297                                        guint         prop_id,
13298                                        const GValue *value,
13299                                        GParamSpec   *pspec)
13300 {
13301   GObject *obj = G_OBJECT (actor);
13302
13303   g_object_freeze_notify (obj);
13304
13305   switch (prop_id)
13306     {
13307     case PROP_X:
13308       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13309       break;
13310
13311     case PROP_Y:
13312       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13313       break;
13314
13315     case PROP_POSITION:
13316       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13317       break;
13318
13319     case PROP_WIDTH:
13320       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13321       break;
13322
13323     case PROP_HEIGHT:
13324       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13325       break;
13326
13327     case PROP_SIZE:
13328       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13329       break;
13330
13331     case PROP_DEPTH:
13332       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13333       break;
13334
13335     case PROP_OPACITY:
13336       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13337       break;
13338
13339     case PROP_BACKGROUND_COLOR:
13340       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13341       break;
13342
13343     case PROP_SCALE_X:
13344       clutter_actor_set_scale_factor_internal (actor,
13345                                                g_value_get_double (value),
13346                                                pspec);
13347       break;
13348
13349     case PROP_SCALE_Y:
13350       clutter_actor_set_scale_factor_internal (actor,
13351                                                g_value_get_double (value),
13352                                                pspec);
13353       break;
13354
13355     case PROP_ROTATION_ANGLE_X:
13356       clutter_actor_set_rotation_angle_internal (actor,
13357                                                  CLUTTER_X_AXIS,
13358                                                  g_value_get_double (value));
13359       break;
13360
13361     case PROP_ROTATION_ANGLE_Y:
13362       clutter_actor_set_rotation_angle_internal (actor,
13363                                                  CLUTTER_Y_AXIS,
13364                                                  g_value_get_double (value));
13365       break;
13366
13367     case PROP_ROTATION_ANGLE_Z:
13368       clutter_actor_set_rotation_angle_internal (actor,
13369                                                  CLUTTER_Z_AXIS,
13370                                                  g_value_get_double (value));
13371       break;
13372
13373     case PROP_CONTENT_BOX:
13374       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13375       break;
13376
13377     default:
13378       g_object_set_property (obj, pspec->name, value);
13379       break;
13380     }
13381
13382   g_object_thaw_notify (obj);
13383 }
13384
13385 static void
13386 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13387                                const gchar       *property_name,
13388                                const GValue      *final)
13389 {
13390   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13391   ClutterActorMeta *meta = NULL;
13392   gchar *p_name = NULL;
13393
13394   meta = get_meta_from_animation_property (actor,
13395                                            property_name,
13396                                            &p_name);
13397   if (meta != NULL)
13398     g_object_set_property (G_OBJECT (meta), p_name, final);
13399   else
13400     {
13401       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13402       GParamSpec *pspec;
13403
13404       pspec = g_object_class_find_property (obj_class, property_name);
13405
13406       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13407         {
13408           /* XXX - I'm going to the special hell for this */
13409           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13410         }
13411       else
13412         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13413     }
13414
13415   g_free (p_name);
13416 }
13417
13418 static void
13419 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13420 {
13421   iface->find_property = clutter_actor_find_property;
13422   iface->get_initial_state = clutter_actor_get_initial_state;
13423   iface->set_final_state = clutter_actor_set_final_state;
13424 }
13425
13426 /**
13427  * clutter_actor_transform_stage_point:
13428  * @self: A #ClutterActor
13429  * @x: (in): x screen coordinate of the point to unproject
13430  * @y: (in): y screen coordinate of the point to unproject
13431  * @x_out: (out): return location for the unprojected x coordinance
13432  * @y_out: (out): return location for the unprojected y coordinance
13433  *
13434  * This function translates screen coordinates (@x, @y) to
13435  * coordinates relative to the actor. For example, it can be used to translate
13436  * screen events from global screen coordinates into actor-local coordinates.
13437  *
13438  * The conversion can fail, notably if the transform stack results in the
13439  * actor being projected on the screen as a mere line.
13440  *
13441  * The conversion should not be expected to be pixel-perfect due to the
13442  * nature of the operation. In general the error grows when the skewing
13443  * of the actor rectangle on screen increases.
13444  *
13445  * <note><para>This function can be computationally intensive.</para></note>
13446  *
13447  * <note><para>This function only works when the allocation is up-to-date,
13448  * i.e. inside of paint().</para></note>
13449  *
13450  * Return value: %TRUE if conversion was successful.
13451  *
13452  * Since: 0.6
13453  */
13454 gboolean
13455 clutter_actor_transform_stage_point (ClutterActor *self,
13456                                      gfloat        x,
13457                                      gfloat        y,
13458                                      gfloat       *x_out,
13459                                      gfloat       *y_out)
13460 {
13461   ClutterVertex v[4];
13462   float ST[3][3];
13463   float RQ[3][3];
13464   int du, dv, xi, yi;
13465   float px, py;
13466   float xf, yf, wf, det;
13467   ClutterActorPrivate *priv;
13468
13469   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13470
13471   priv = self->priv;
13472
13473   /* This implementation is based on the quad -> quad projection algorithm
13474    * described by Paul Heckbert in:
13475    *
13476    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13477    *
13478    * and the sample implementation at:
13479    *
13480    *   http://www.cs.cmu.edu/~ph/src/texfund/
13481    *
13482    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13483    * quad to rectangle only, which significantly simplifies things; the
13484    * function calls have been unrolled, and most of the math is done in fixed
13485    * point.
13486    */
13487
13488   clutter_actor_get_abs_allocation_vertices (self, v);
13489
13490   /* Keeping these as ints simplifies the multiplication (no significant
13491    * loss of precision here).
13492    */
13493   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13494   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13495
13496   if (!du || !dv)
13497     return FALSE;
13498
13499 #define UX2FP(x)        (x)
13500 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13501
13502   /* First, find mapping from unit uv square to xy quadrilateral; this
13503    * equivalent to the pmap_square_quad() functions in the sample
13504    * implementation, which we can simplify, since our target is always
13505    * a rectangle.
13506    */
13507   px = v[0].x - v[1].x + v[3].x - v[2].x;
13508   py = v[0].y - v[1].y + v[3].y - v[2].y;
13509
13510   if (!px && !py)
13511     {
13512       /* affine transform */
13513       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13514       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13515       RQ[2][0] = UX2FP (v[0].x);
13516       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13517       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13518       RQ[2][1] = UX2FP (v[0].y);
13519       RQ[0][2] = 0;
13520       RQ[1][2] = 0;
13521       RQ[2][2] = 1.0;
13522     }
13523   else
13524     {
13525       /* projective transform */
13526       double dx1, dx2, dy1, dy2, del;
13527
13528       dx1 = UX2FP (v[1].x - v[3].x);
13529       dx2 = UX2FP (v[2].x - v[3].x);
13530       dy1 = UX2FP (v[1].y - v[3].y);
13531       dy2 = UX2FP (v[2].y - v[3].y);
13532
13533       del = DET2FP (dx1, dx2, dy1, dy2);
13534       if (!del)
13535         return FALSE;
13536
13537       /*
13538        * The division here needs to be done in floating point for
13539        * precisions reasons.
13540        */
13541       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13542       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13543       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13544       RQ[2][2] = 1.0;
13545       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13546       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13547       RQ[2][0] = UX2FP (v[0].x);
13548       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13549       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13550       RQ[2][1] = UX2FP (v[0].y);
13551     }
13552
13553   /*
13554    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13555    * square. Since our rectangle is based at 0,0 we only need to scale.
13556    */
13557   RQ[0][0] /= du;
13558   RQ[1][0] /= dv;
13559   RQ[0][1] /= du;
13560   RQ[1][1] /= dv;
13561   RQ[0][2] /= du;
13562   RQ[1][2] /= dv;
13563
13564   /*
13565    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13566    * inverse of that.
13567    */
13568   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13569   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13570   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13571   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13572   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13573   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13574   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13575   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13576   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13577
13578   /*
13579    * Check the resulting matrix is OK.
13580    */
13581   det = (RQ[0][0] * ST[0][0])
13582       + (RQ[0][1] * ST[0][1])
13583       + (RQ[0][2] * ST[0][2]);
13584   if (!det)
13585     return FALSE;
13586
13587   /*
13588    * Now transform our point with the ST matrix; the notional w
13589    * coordinate is 1, hence the last part is simply added.
13590    */
13591   xi = (int) x;
13592   yi = (int) y;
13593
13594   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13595   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13596   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13597
13598   if (x_out)
13599     *x_out = xf / wf;
13600
13601   if (y_out)
13602     *y_out = yf / wf;
13603
13604 #undef UX2FP
13605 #undef DET2FP
13606
13607   return TRUE;
13608 }
13609
13610 /**
13611  * clutter_actor_is_rotated:
13612  * @self: a #ClutterActor
13613  *
13614  * Checks whether any rotation is applied to the actor.
13615  *
13616  * Return value: %TRUE if the actor is rotated.
13617  *
13618  * Since: 0.6
13619  */
13620 gboolean
13621 clutter_actor_is_rotated (ClutterActor *self)
13622 {
13623   const ClutterTransformInfo *info;
13624
13625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13626
13627   info = _clutter_actor_get_transform_info_or_defaults (self);
13628
13629   if (info->rx_angle || info->ry_angle || info->rz_angle)
13630     return TRUE;
13631
13632   return FALSE;
13633 }
13634
13635 /**
13636  * clutter_actor_is_scaled:
13637  * @self: a #ClutterActor
13638  *
13639  * Checks whether the actor is scaled in either dimension.
13640  *
13641  * Return value: %TRUE if the actor is scaled.
13642  *
13643  * Since: 0.6
13644  */
13645 gboolean
13646 clutter_actor_is_scaled (ClutterActor *self)
13647 {
13648   const ClutterTransformInfo *info;
13649
13650   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13651
13652   info = _clutter_actor_get_transform_info_or_defaults (self);
13653
13654   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13655     return TRUE;
13656
13657   return FALSE;
13658 }
13659
13660 ClutterActor *
13661 _clutter_actor_get_stage_internal (ClutterActor *actor)
13662 {
13663   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13664     actor = actor->priv->parent;
13665
13666   return actor;
13667 }
13668
13669 /**
13670  * clutter_actor_get_stage:
13671  * @actor: a #ClutterActor
13672  *
13673  * Retrieves the #ClutterStage where @actor is contained.
13674  *
13675  * Return value: (transfer none) (type Clutter.Stage): the stage
13676  *   containing the actor, or %NULL
13677  *
13678  * Since: 0.8
13679  */
13680 ClutterActor *
13681 clutter_actor_get_stage (ClutterActor *actor)
13682 {
13683   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13684
13685   return _clutter_actor_get_stage_internal (actor);
13686 }
13687
13688 /**
13689  * clutter_actor_allocate_available_size:
13690  * @self: a #ClutterActor
13691  * @x: the actor's X coordinate
13692  * @y: the actor's Y coordinate
13693  * @available_width: the maximum available width, or -1 to use the
13694  *   actor's natural width
13695  * @available_height: the maximum available height, or -1 to use the
13696  *   actor's natural height
13697  * @flags: flags controlling the allocation
13698  *
13699  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13700  * preferred size, but limiting it to the maximum available width
13701  * and height provided.
13702  *
13703  * This function will do the right thing when dealing with the
13704  * actor's request mode.
13705  *
13706  * The implementation of this function is equivalent to:
13707  *
13708  * |[
13709  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13710  *     {
13711  *       clutter_actor_get_preferred_width (self, available_height,
13712  *                                          &amp;min_width,
13713  *                                          &amp;natural_width);
13714  *       width = CLAMP (natural_width, min_width, available_width);
13715  *
13716  *       clutter_actor_get_preferred_height (self, width,
13717  *                                           &amp;min_height,
13718  *                                           &amp;natural_height);
13719  *       height = CLAMP (natural_height, min_height, available_height);
13720  *     }
13721  *   else
13722  *     {
13723  *       clutter_actor_get_preferred_height (self, available_width,
13724  *                                           &amp;min_height,
13725  *                                           &amp;natural_height);
13726  *       height = CLAMP (natural_height, min_height, available_height);
13727  *
13728  *       clutter_actor_get_preferred_width (self, height,
13729  *                                          &amp;min_width,
13730  *                                          &amp;natural_width);
13731  *       width = CLAMP (natural_width, min_width, available_width);
13732  *     }
13733  *
13734  *   box.x1 = x; box.y1 = y;
13735  *   box.x2 = box.x1 + available_width;
13736  *   box.y2 = box.y1 + available_height;
13737  *   clutter_actor_allocate (self, &amp;box, flags);
13738  * ]|
13739  *
13740  * This function can be used by fluid layout managers to allocate
13741  * an actor's preferred size without making it bigger than the area
13742  * available for the container.
13743  *
13744  * Since: 1.0
13745  */
13746 void
13747 clutter_actor_allocate_available_size (ClutterActor           *self,
13748                                        gfloat                  x,
13749                                        gfloat                  y,
13750                                        gfloat                  available_width,
13751                                        gfloat                  available_height,
13752                                        ClutterAllocationFlags  flags)
13753 {
13754   ClutterActorPrivate *priv;
13755   gfloat width, height;
13756   gfloat min_width, min_height;
13757   gfloat natural_width, natural_height;
13758   ClutterActorBox box;
13759
13760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761
13762   priv = self->priv;
13763
13764   width = height = 0.0;
13765
13766   switch (priv->request_mode)
13767     {
13768     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13769       clutter_actor_get_preferred_width (self, available_height,
13770                                          &min_width,
13771                                          &natural_width);
13772       width  = CLAMP (natural_width, min_width, available_width);
13773
13774       clutter_actor_get_preferred_height (self, width,
13775                                           &min_height,
13776                                           &natural_height);
13777       height = CLAMP (natural_height, min_height, available_height);
13778       break;
13779
13780     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13781       clutter_actor_get_preferred_height (self, available_width,
13782                                           &min_height,
13783                                           &natural_height);
13784       height = CLAMP (natural_height, min_height, available_height);
13785
13786       clutter_actor_get_preferred_width (self, height,
13787                                          &min_width,
13788                                          &natural_width);
13789       width  = CLAMP (natural_width, min_width, available_width);
13790       break;
13791     }
13792
13793
13794   box.x1 = x;
13795   box.y1 = y;
13796   box.x2 = box.x1 + width;
13797   box.y2 = box.y1 + height;
13798   clutter_actor_allocate (self, &box, flags);
13799 }
13800
13801 /**
13802  * clutter_actor_allocate_preferred_size:
13803  * @self: a #ClutterActor
13804  * @flags: flags controlling the allocation
13805  *
13806  * Allocates the natural size of @self.
13807  *
13808  * This function is a utility call for #ClutterActor implementations
13809  * that allocates the actor's preferred natural size. It can be used
13810  * by fixed layout managers (like #ClutterGroup or so called
13811  * 'composite actors') inside the ClutterActor::allocate
13812  * implementation to give each child exactly how much space it
13813  * requires.
13814  *
13815  * This function is not meant to be used by applications. It is also
13816  * not meant to be used outside the implementation of the
13817  * ClutterActor::allocate virtual function.
13818  *
13819  * Since: 0.8
13820  */
13821 void
13822 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13823                                        ClutterAllocationFlags  flags)
13824 {
13825   gfloat actor_x, actor_y;
13826   gfloat natural_width, natural_height;
13827   ClutterActorBox actor_box;
13828
13829   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13830
13831   actor_x = clutter_actor_get_x (self);
13832   actor_y = clutter_actor_get_y (self);
13833
13834   clutter_actor_get_preferred_size (self,
13835                                     NULL, NULL,
13836                                     &natural_width,
13837                                     &natural_height);
13838
13839   actor_box.x1 = actor_x;
13840   actor_box.y1 = actor_y;
13841   actor_box.x2 = actor_box.x1 + natural_width;
13842   actor_box.y2 = actor_box.y1 + natural_height;
13843
13844   clutter_actor_allocate (self, &actor_box, flags);
13845 }
13846
13847 /**
13848  * clutter_actor_allocate_align_fill:
13849  * @self: a #ClutterActor
13850  * @box: a #ClutterActorBox, containing the available width and height
13851  * @x_align: the horizontal alignment, between 0 and 1
13852  * @y_align: the vertical alignment, between 0 and 1
13853  * @x_fill: whether the actor should fill horizontally
13854  * @y_fill: whether the actor should fill vertically
13855  * @flags: allocation flags to be passed to clutter_actor_allocate()
13856  *
13857  * Allocates @self by taking into consideration the available allocation
13858  * area; an alignment factor on either axis; and whether the actor should
13859  * fill the allocation on either axis.
13860  *
13861  * The @box should contain the available allocation width and height;
13862  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13863  * allocation will be offset by their value.
13864  *
13865  * This function takes into consideration the geometry request specified by
13866  * the #ClutterActor:request-mode property, and the text direction.
13867  *
13868  * This function is useful for fluid layout managers, like #ClutterBinLayout
13869  * or #ClutterTableLayout
13870  *
13871  * Since: 1.4
13872  */
13873 void
13874 clutter_actor_allocate_align_fill (ClutterActor           *self,
13875                                    const ClutterActorBox  *box,
13876                                    gdouble                 x_align,
13877                                    gdouble                 y_align,
13878                                    gboolean                x_fill,
13879                                    gboolean                y_fill,
13880                                    ClutterAllocationFlags  flags)
13881 {
13882   ClutterActorPrivate *priv;
13883   ClutterActorBox allocation = { 0, };
13884   gfloat x_offset, y_offset;
13885   gfloat available_width, available_height;
13886   gfloat child_width, child_height;
13887
13888   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13889   g_return_if_fail (box != NULL);
13890   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13891   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13892
13893   priv = self->priv;
13894
13895   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13896   clutter_actor_box_get_size (box, &available_width, &available_height);
13897
13898   if (available_width < 0)
13899     available_width = 0;
13900
13901   if (available_height < 0)
13902     available_height = 0;
13903
13904   if (x_fill)
13905     {
13906       allocation.x1 = x_offset;
13907       allocation.x2 = allocation.x1 + available_width;
13908     }
13909
13910   if (y_fill)
13911     {
13912       allocation.y1 = y_offset;
13913       allocation.y2 = allocation.y1 + available_height;
13914     }
13915
13916   /* if we are filling horizontally and vertically then we're done */
13917   if (x_fill && y_fill)
13918     goto out;
13919
13920   child_width = child_height = 0.0f;
13921
13922   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13923     {
13924       gfloat min_width, natural_width;
13925       gfloat min_height, natural_height;
13926
13927       clutter_actor_get_preferred_width (self, available_height,
13928                                          &min_width,
13929                                          &natural_width);
13930
13931       child_width = CLAMP (natural_width, min_width, available_width);
13932
13933       if (!y_fill)
13934         {
13935           clutter_actor_get_preferred_height (self, child_width,
13936                                               &min_height,
13937                                               &natural_height);
13938
13939           child_height = CLAMP (natural_height, min_height, available_height);
13940         }
13941     }
13942   else
13943     {
13944       gfloat min_width, natural_width;
13945       gfloat min_height, natural_height;
13946
13947       clutter_actor_get_preferred_height (self, available_width,
13948                                           &min_height,
13949                                           &natural_height);
13950
13951       child_height = CLAMP (natural_height, min_height, available_height);
13952
13953       if (!x_fill)
13954         {
13955           clutter_actor_get_preferred_width (self, child_height,
13956                                              &min_width,
13957                                              &natural_width);
13958
13959           child_width = CLAMP (natural_width, min_width, available_width);
13960         }
13961     }
13962
13963   /* invert the horizontal alignment for RTL languages */
13964   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13965     x_align = 1.0 - x_align;
13966
13967   if (!x_fill)
13968     {
13969       allocation.x1 = x_offset
13970                     + ((available_width - child_width) * x_align);
13971       allocation.x2 = allocation.x1 + child_width;
13972     }
13973
13974   if (!y_fill)
13975     {
13976       allocation.y1 = y_offset
13977                     + ((available_height - child_height) * y_align);
13978       allocation.y2 = allocation.y1 + child_height;
13979     }
13980
13981 out:
13982   clutter_actor_box_clamp_to_pixel (&allocation);
13983   clutter_actor_allocate (self, &allocation, flags);
13984 }
13985
13986 /**
13987  * clutter_actor_grab_key_focus:
13988  * @self: a #ClutterActor
13989  *
13990  * Sets the key focus of the #ClutterStage including @self
13991  * to this #ClutterActor.
13992  *
13993  * Since: 1.0
13994  */
13995 void
13996 clutter_actor_grab_key_focus (ClutterActor *self)
13997 {
13998   ClutterActor *stage;
13999
14000   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14001
14002   stage = _clutter_actor_get_stage_internal (self);
14003   if (stage != NULL)
14004     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14005 }
14006
14007 /**
14008  * clutter_actor_get_pango_context:
14009  * @self: a #ClutterActor
14010  *
14011  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14012  * is already configured using the appropriate font map, resolution
14013  * and font options.
14014  *
14015  * Unlike clutter_actor_create_pango_context(), this context is owend
14016  * by the #ClutterActor and it will be updated each time the options
14017  * stored by the #ClutterBackend change.
14018  *
14019  * You can use the returned #PangoContext to create a #PangoLayout
14020  * and render text using cogl_pango_render_layout() to reuse the
14021  * glyphs cache also used by Clutter.
14022  *
14023  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14024  *   The returned #PangoContext is owned by the actor and should not be
14025  *   unreferenced by the application code
14026  *
14027  * Since: 1.0
14028  */
14029 PangoContext *
14030 clutter_actor_get_pango_context (ClutterActor *self)
14031 {
14032   ClutterActorPrivate *priv;
14033
14034   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14035
14036   priv = self->priv;
14037
14038   if (priv->pango_context != NULL)
14039     return priv->pango_context;
14040
14041   priv->pango_context = _clutter_context_get_pango_context ();
14042   g_object_ref (priv->pango_context);
14043
14044   return priv->pango_context;
14045 }
14046
14047 /**
14048  * clutter_actor_create_pango_context:
14049  * @self: a #ClutterActor
14050  *
14051  * Creates a #PangoContext for the given actor. The #PangoContext
14052  * is already configured using the appropriate font map, resolution
14053  * and font options.
14054  *
14055  * See also clutter_actor_get_pango_context().
14056  *
14057  * Return value: (transfer full): the newly created #PangoContext.
14058  *   Use g_object_unref() on the returned value to deallocate its
14059  *   resources
14060  *
14061  * Since: 1.0
14062  */
14063 PangoContext *
14064 clutter_actor_create_pango_context (ClutterActor *self)
14065 {
14066   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14067
14068   return _clutter_context_create_pango_context ();
14069 }
14070
14071 /**
14072  * clutter_actor_create_pango_layout:
14073  * @self: a #ClutterActor
14074  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14075  *
14076  * Creates a new #PangoLayout from the same #PangoContext used
14077  * by the #ClutterActor. The #PangoLayout is already configured
14078  * with the font map, resolution and font options, and the
14079  * given @text.
14080  *
14081  * If you want to keep around a #PangoLayout created by this
14082  * function you will have to connect to the #ClutterBackend::font-changed
14083  * and #ClutterBackend::resolution-changed signals, and call
14084  * pango_layout_context_changed() in response to them.
14085  *
14086  * Return value: (transfer full): the newly created #PangoLayout.
14087  *   Use g_object_unref() when done
14088  *
14089  * Since: 1.0
14090  */
14091 PangoLayout *
14092 clutter_actor_create_pango_layout (ClutterActor *self,
14093                                    const gchar  *text)
14094 {
14095   PangoContext *context;
14096   PangoLayout *layout;
14097
14098   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14099
14100   context = clutter_actor_get_pango_context (self);
14101   layout = pango_layout_new (context);
14102
14103   if (text)
14104     pango_layout_set_text (layout, text, -1);
14105
14106   return layout;
14107 }
14108
14109 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14110  * ClutterOffscreenEffect.
14111  */
14112 void
14113 _clutter_actor_set_opacity_override (ClutterActor *self,
14114                                      gint          opacity)
14115 {
14116   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14117
14118   self->priv->opacity_override = opacity;
14119 }
14120
14121 gint
14122 _clutter_actor_get_opacity_override (ClutterActor *self)
14123 {
14124   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14125
14126   return self->priv->opacity_override;
14127 }
14128
14129 /* Allows you to disable applying the actors model view transform during
14130  * a paint. Used by ClutterClone. */
14131 void
14132 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14133                                                 gboolean      enable)
14134 {
14135   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14136
14137   self->priv->enable_model_view_transform = enable;
14138 }
14139
14140 void
14141 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14142                                           gboolean      enable)
14143 {
14144   ClutterActorPrivate *priv;
14145
14146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14147
14148   priv = self->priv;
14149
14150   priv->enable_paint_unmapped = enable;
14151
14152   if (priv->enable_paint_unmapped)
14153     {
14154       /* Make sure that the parents of the widget are realized first;
14155        * otherwise checks in clutter_actor_update_map_state() will
14156        * fail.
14157        */
14158       clutter_actor_realize (self);
14159
14160       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14161     }
14162   else
14163     {
14164       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14165     }
14166 }
14167
14168 static void
14169 clutter_anchor_coord_get_units (ClutterActor      *self,
14170                                 const AnchorCoord *coord,
14171                                 gfloat            *x,
14172                                 gfloat            *y,
14173                                 gfloat            *z)
14174 {
14175   if (coord->is_fractional)
14176     {
14177       gfloat actor_width, actor_height;
14178
14179       clutter_actor_get_size (self, &actor_width, &actor_height);
14180
14181       if (x)
14182         *x = actor_width * coord->v.fraction.x;
14183
14184       if (y)
14185         *y = actor_height * coord->v.fraction.y;
14186
14187       if (z)
14188         *z = 0;
14189     }
14190   else
14191     {
14192       if (x)
14193         *x = coord->v.units.x;
14194
14195       if (y)
14196         *y = coord->v.units.y;
14197
14198       if (z)
14199         *z = coord->v.units.z;
14200     }
14201 }
14202
14203 static void
14204 clutter_anchor_coord_set_units (AnchorCoord *coord,
14205                                 gfloat       x,
14206                                 gfloat       y,
14207                                 gfloat       z)
14208 {
14209   coord->is_fractional = FALSE;
14210   coord->v.units.x = x;
14211   coord->v.units.y = y;
14212   coord->v.units.z = z;
14213 }
14214
14215 static ClutterGravity
14216 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14217 {
14218   if (coord->is_fractional)
14219     {
14220       if (coord->v.fraction.x == 0.0)
14221         {
14222           if (coord->v.fraction.y == 0.0)
14223             return CLUTTER_GRAVITY_NORTH_WEST;
14224           else if (coord->v.fraction.y == 0.5)
14225             return CLUTTER_GRAVITY_WEST;
14226           else if (coord->v.fraction.y == 1.0)
14227             return CLUTTER_GRAVITY_SOUTH_WEST;
14228           else
14229             return CLUTTER_GRAVITY_NONE;
14230         }
14231       else if (coord->v.fraction.x == 0.5)
14232         {
14233           if (coord->v.fraction.y == 0.0)
14234             return CLUTTER_GRAVITY_NORTH;
14235           else if (coord->v.fraction.y == 0.5)
14236             return CLUTTER_GRAVITY_CENTER;
14237           else if (coord->v.fraction.y == 1.0)
14238             return CLUTTER_GRAVITY_SOUTH;
14239           else
14240             return CLUTTER_GRAVITY_NONE;
14241         }
14242       else if (coord->v.fraction.x == 1.0)
14243         {
14244           if (coord->v.fraction.y == 0.0)
14245             return CLUTTER_GRAVITY_NORTH_EAST;
14246           else if (coord->v.fraction.y == 0.5)
14247             return CLUTTER_GRAVITY_EAST;
14248           else if (coord->v.fraction.y == 1.0)
14249             return CLUTTER_GRAVITY_SOUTH_EAST;
14250           else
14251             return CLUTTER_GRAVITY_NONE;
14252         }
14253       else
14254         return CLUTTER_GRAVITY_NONE;
14255     }
14256   else
14257     return CLUTTER_GRAVITY_NONE;
14258 }
14259
14260 static void
14261 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14262                                   ClutterGravity  gravity)
14263 {
14264   switch (gravity)
14265     {
14266     case CLUTTER_GRAVITY_NORTH:
14267       coord->v.fraction.x = 0.5;
14268       coord->v.fraction.y = 0.0;
14269       break;
14270
14271     case CLUTTER_GRAVITY_NORTH_EAST:
14272       coord->v.fraction.x = 1.0;
14273       coord->v.fraction.y = 0.0;
14274       break;
14275
14276     case CLUTTER_GRAVITY_EAST:
14277       coord->v.fraction.x = 1.0;
14278       coord->v.fraction.y = 0.5;
14279       break;
14280
14281     case CLUTTER_GRAVITY_SOUTH_EAST:
14282       coord->v.fraction.x = 1.0;
14283       coord->v.fraction.y = 1.0;
14284       break;
14285
14286     case CLUTTER_GRAVITY_SOUTH:
14287       coord->v.fraction.x = 0.5;
14288       coord->v.fraction.y = 1.0;
14289       break;
14290
14291     case CLUTTER_GRAVITY_SOUTH_WEST:
14292       coord->v.fraction.x = 0.0;
14293       coord->v.fraction.y = 1.0;
14294       break;
14295
14296     case CLUTTER_GRAVITY_WEST:
14297       coord->v.fraction.x = 0.0;
14298       coord->v.fraction.y = 0.5;
14299       break;
14300
14301     case CLUTTER_GRAVITY_NORTH_WEST:
14302       coord->v.fraction.x = 0.0;
14303       coord->v.fraction.y = 0.0;
14304       break;
14305
14306     case CLUTTER_GRAVITY_CENTER:
14307       coord->v.fraction.x = 0.5;
14308       coord->v.fraction.y = 0.5;
14309       break;
14310
14311     default:
14312       coord->v.fraction.x = 0.0;
14313       coord->v.fraction.y = 0.0;
14314       break;
14315     }
14316
14317   coord->is_fractional = TRUE;
14318 }
14319
14320 static gboolean
14321 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14322 {
14323   if (coord->is_fractional)
14324     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14325   else
14326     return (coord->v.units.x == 0.0
14327             && coord->v.units.y == 0.0
14328             && coord->v.units.z == 0.0);
14329 }
14330
14331 /**
14332  * clutter_actor_get_flags:
14333  * @self: a #ClutterActor
14334  *
14335  * Retrieves the flags set on @self
14336  *
14337  * Return value: a bitwise or of #ClutterActorFlags or 0
14338  *
14339  * Since: 1.0
14340  */
14341 ClutterActorFlags
14342 clutter_actor_get_flags (ClutterActor *self)
14343 {
14344   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14345
14346   return self->flags;
14347 }
14348
14349 /**
14350  * clutter_actor_set_flags:
14351  * @self: a #ClutterActor
14352  * @flags: the flags to set
14353  *
14354  * Sets @flags on @self
14355  *
14356  * This function will emit notifications for the changed properties
14357  *
14358  * Since: 1.0
14359  */
14360 void
14361 clutter_actor_set_flags (ClutterActor      *self,
14362                          ClutterActorFlags  flags)
14363 {
14364   ClutterActorFlags old_flags;
14365   GObject *obj;
14366   gboolean was_reactive_set, reactive_set;
14367   gboolean was_realized_set, realized_set;
14368   gboolean was_mapped_set, mapped_set;
14369   gboolean was_visible_set, visible_set;
14370
14371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14372
14373   if (self->flags == flags)
14374     return;
14375
14376   obj = G_OBJECT (self);
14377   g_object_ref (obj);
14378   g_object_freeze_notify (obj);
14379
14380   old_flags = self->flags;
14381
14382   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14383   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14384   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14385   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14386
14387   self->flags |= flags;
14388
14389   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14390   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14391   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14392   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14393
14394   if (reactive_set != was_reactive_set)
14395     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14396
14397   if (realized_set != was_realized_set)
14398     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14399
14400   if (mapped_set != was_mapped_set)
14401     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14402
14403   if (visible_set != was_visible_set)
14404     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14405
14406   g_object_thaw_notify (obj);
14407   g_object_unref (obj);
14408 }
14409
14410 /**
14411  * clutter_actor_unset_flags:
14412  * @self: a #ClutterActor
14413  * @flags: the flags to unset
14414  *
14415  * Unsets @flags on @self
14416  *
14417  * This function will emit notifications for the changed properties
14418  *
14419  * Since: 1.0
14420  */
14421 void
14422 clutter_actor_unset_flags (ClutterActor      *self,
14423                            ClutterActorFlags  flags)
14424 {
14425   ClutterActorFlags old_flags;
14426   GObject *obj;
14427   gboolean was_reactive_set, reactive_set;
14428   gboolean was_realized_set, realized_set;
14429   gboolean was_mapped_set, mapped_set;
14430   gboolean was_visible_set, visible_set;
14431
14432   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14433
14434   obj = G_OBJECT (self);
14435   g_object_freeze_notify (obj);
14436
14437   old_flags = self->flags;
14438
14439   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14440   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14441   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14442   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14443
14444   self->flags &= ~flags;
14445
14446   if (self->flags == old_flags)
14447     return;
14448
14449   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14450   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14451   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14452   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14453
14454   if (reactive_set != was_reactive_set)
14455     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14456
14457   if (realized_set != was_realized_set)
14458     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14459
14460   if (mapped_set != was_mapped_set)
14461     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14462
14463   if (visible_set != was_visible_set)
14464     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14465
14466   g_object_thaw_notify (obj);
14467 }
14468
14469 /**
14470  * clutter_actor_get_transformation_matrix:
14471  * @self: a #ClutterActor
14472  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14473  *
14474  * Retrieves the transformations applied to @self relative to its
14475  * parent.
14476  *
14477  * Since: 1.0
14478  */
14479 void
14480 clutter_actor_get_transformation_matrix (ClutterActor *self,
14481                                          CoglMatrix   *matrix)
14482 {
14483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14484
14485   cogl_matrix_init_identity (matrix);
14486
14487   _clutter_actor_apply_modelview_transform (self, matrix);
14488 }
14489
14490 void
14491 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14492                                    gboolean      is_in_clone_paint)
14493 {
14494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14495   self->priv->in_clone_paint = is_in_clone_paint;
14496 }
14497
14498 /**
14499  * clutter_actor_is_in_clone_paint:
14500  * @self: a #ClutterActor
14501  *
14502  * Checks whether @self is being currently painted by a #ClutterClone
14503  *
14504  * This function is useful only inside the ::paint virtual function
14505  * implementations or within handlers for the #ClutterActor::paint
14506  * signal
14507  *
14508  * This function should not be used by applications
14509  *
14510  * Return value: %TRUE if the #ClutterActor is currently being painted
14511  *   by a #ClutterClone, and %FALSE otherwise
14512  *
14513  * Since: 1.0
14514  */
14515 gboolean
14516 clutter_actor_is_in_clone_paint (ClutterActor *self)
14517 {
14518   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14519
14520   return self->priv->in_clone_paint;
14521 }
14522
14523 static gboolean
14524 set_direction_recursive (ClutterActor *actor,
14525                          gpointer      user_data)
14526 {
14527   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14528
14529   clutter_actor_set_text_direction (actor, text_dir);
14530
14531   return TRUE;
14532 }
14533
14534 /**
14535  * clutter_actor_set_text_direction:
14536  * @self: a #ClutterActor
14537  * @text_dir: the text direction for @self
14538  *
14539  * Sets the #ClutterTextDirection for an actor
14540  *
14541  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14542  *
14543  * If @self implements #ClutterContainer then this function will recurse
14544  * inside all the children of @self (including the internal ones).
14545  *
14546  * Composite actors not implementing #ClutterContainer, or actors requiring
14547  * special handling when the text direction changes, should connect to
14548  * the #GObject::notify signal for the #ClutterActor:text-direction property
14549  *
14550  * Since: 1.2
14551  */
14552 void
14553 clutter_actor_set_text_direction (ClutterActor         *self,
14554                                   ClutterTextDirection  text_dir)
14555 {
14556   ClutterActorPrivate *priv;
14557
14558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14559   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14560
14561   priv = self->priv;
14562
14563   if (priv->text_direction != text_dir)
14564     {
14565       priv->text_direction = text_dir;
14566
14567       /* we need to emit the notify::text-direction first, so that
14568        * the sub-classes can catch that and do specific handling of
14569        * the text direction; see clutter_text_direction_changed_cb()
14570        * inside clutter-text.c
14571        */
14572       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14573
14574       _clutter_actor_foreach_child (self, set_direction_recursive,
14575                                     GINT_TO_POINTER (text_dir));
14576
14577       clutter_actor_queue_relayout (self);
14578     }
14579 }
14580
14581 void
14582 _clutter_actor_set_has_pointer (ClutterActor *self,
14583                                 gboolean      has_pointer)
14584 {
14585   ClutterActorPrivate *priv = self->priv;
14586
14587   if (priv->has_pointer != has_pointer)
14588     {
14589       priv->has_pointer = has_pointer;
14590
14591       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14592     }
14593 }
14594
14595 /**
14596  * clutter_actor_get_text_direction:
14597  * @self: a #ClutterActor
14598  *
14599  * Retrieves the value set using clutter_actor_set_text_direction()
14600  *
14601  * If no text direction has been previously set, the default text
14602  * direction, as returned by clutter_get_default_text_direction(), will
14603  * be returned instead
14604  *
14605  * Return value: the #ClutterTextDirection for the actor
14606  *
14607  * Since: 1.2
14608  */
14609 ClutterTextDirection
14610 clutter_actor_get_text_direction (ClutterActor *self)
14611 {
14612   ClutterActorPrivate *priv;
14613
14614   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14615                         CLUTTER_TEXT_DIRECTION_LTR);
14616
14617   priv = self->priv;
14618
14619   /* if no direction has been set yet use the default */
14620   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14621     priv->text_direction = clutter_get_default_text_direction ();
14622
14623   return priv->text_direction;
14624 }
14625
14626 /**
14627  * clutter_actor_push_internal:
14628  * @self: a #ClutterActor
14629  *
14630  * Should be used by actors implementing the #ClutterContainer and with
14631  * internal children added through clutter_actor_set_parent(), for instance:
14632  *
14633  * |[
14634  *   static void
14635  *   my_actor_init (MyActor *self)
14636  *   {
14637  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14638  *
14639  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14640  *
14641  *     /&ast; calling clutter_actor_set_parent() now will result in
14642  *      &ast; the internal flag being set on a child of MyActor
14643  *      &ast;/
14644  *
14645  *     /&ast; internal child - a background texture &ast;/
14646  *     self->priv->background_tex = clutter_texture_new ();
14647  *     clutter_actor_set_parent (self->priv->background_tex,
14648  *                               CLUTTER_ACTOR (self));
14649  *
14650  *     /&ast; internal child - a label &ast;/
14651  *     self->priv->label = clutter_text_new ();
14652  *     clutter_actor_set_parent (self->priv->label,
14653  *                               CLUTTER_ACTOR (self));
14654  *
14655  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14656  *
14657  *     /&ast; calling clutter_actor_set_parent() now will not result in
14658  *      &ast; the internal flag being set on a child of MyActor
14659  *      &ast;/
14660  *   }
14661  * ]|
14662  *
14663  * This function will be used by Clutter to toggle an "internal child"
14664  * flag whenever clutter_actor_set_parent() is called; internal children
14665  * are handled differently by Clutter, specifically when destroying their
14666  * parent.
14667  *
14668  * Call clutter_actor_pop_internal() when you finished adding internal
14669  * children.
14670  *
14671  * Nested calls to clutter_actor_push_internal() are allowed, but each
14672  * one must by followed by a clutter_actor_pop_internal() call.
14673  *
14674  * Since: 1.2
14675  *
14676  * Deprecated: 1.10: All children of an actor are accessible through
14677  *   the #ClutterActor API, and #ClutterActor implements the
14678  *   #ClutterContainer interface, so this function is only useful
14679  *   for legacy containers overriding the default implementation.
14680  */
14681 void
14682 clutter_actor_push_internal (ClutterActor *self)
14683 {
14684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14685
14686   self->priv->internal_child += 1;
14687 }
14688
14689 /**
14690  * clutter_actor_pop_internal:
14691  * @self: a #ClutterActor
14692  *
14693  * Disables the effects of clutter_actor_push_internal().
14694  *
14695  * Since: 1.2
14696  *
14697  * Deprecated: 1.10: All children of an actor are accessible through
14698  *   the #ClutterActor API. This function is only useful for legacy
14699  *   containers overriding the default implementation of the
14700  *   #ClutterContainer interface.
14701  */
14702 void
14703 clutter_actor_pop_internal (ClutterActor *self)
14704 {
14705   ClutterActorPrivate *priv;
14706
14707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14708
14709   priv = self->priv;
14710
14711   if (priv->internal_child == 0)
14712     {
14713       g_warning ("Mismatched %s: you need to call "
14714                  "clutter_actor_push_composite() at least once before "
14715                  "calling this function", G_STRFUNC);
14716       return;
14717     }
14718
14719   priv->internal_child -= 1;
14720 }
14721
14722 /**
14723  * clutter_actor_has_pointer:
14724  * @self: a #ClutterActor
14725  *
14726  * Checks whether an actor contains the pointer of a
14727  * #ClutterInputDevice
14728  *
14729  * Return value: %TRUE if the actor contains the pointer, and
14730  *   %FALSE otherwise
14731  *
14732  * Since: 1.2
14733  */
14734 gboolean
14735 clutter_actor_has_pointer (ClutterActor *self)
14736 {
14737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14738
14739   return self->priv->has_pointer;
14740 }
14741
14742 /* XXX: This is a workaround for not being able to break the ABI of
14743  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14744  * clutter_actor_queue_clipped_redraw() for details.
14745  */
14746 ClutterPaintVolume *
14747 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14748 {
14749   return g_object_get_data (G_OBJECT (self),
14750                             "-clutter-actor-queue-redraw-clip");
14751 }
14752
14753 void
14754 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14755                                       ClutterPaintVolume *clip)
14756 {
14757   g_object_set_data (G_OBJECT (self),
14758                      "-clutter-actor-queue-redraw-clip",
14759                      clip);
14760 }
14761
14762 /**
14763  * clutter_actor_has_allocation:
14764  * @self: a #ClutterActor
14765  *
14766  * Checks if the actor has an up-to-date allocation assigned to
14767  * it. This means that the actor should have an allocation: it's
14768  * visible and has a parent. It also means that there is no
14769  * outstanding relayout request in progress for the actor or its
14770  * children (There might be other outstanding layout requests in
14771  * progress that will cause the actor to get a new allocation
14772  * when the stage is laid out, however).
14773  *
14774  * If this function returns %FALSE, then the actor will normally
14775  * be allocated before it is next drawn on the screen.
14776  *
14777  * Return value: %TRUE if the actor has an up-to-date allocation
14778  *
14779  * Since: 1.4
14780  */
14781 gboolean
14782 clutter_actor_has_allocation (ClutterActor *self)
14783 {
14784   ClutterActorPrivate *priv;
14785
14786   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14787
14788   priv = self->priv;
14789
14790   return priv->parent != NULL &&
14791          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14792          !priv->needs_allocation;
14793 }
14794
14795 /**
14796  * clutter_actor_add_action:
14797  * @self: a #ClutterActor
14798  * @action: a #ClutterAction
14799  *
14800  * Adds @action to the list of actions applied to @self
14801  *
14802  * A #ClutterAction can only belong to one actor at a time
14803  *
14804  * The #ClutterActor will hold a reference on @action until either
14805  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14806  * is called
14807  *
14808  * Since: 1.4
14809  */
14810 void
14811 clutter_actor_add_action (ClutterActor  *self,
14812                           ClutterAction *action)
14813 {
14814   ClutterActorPrivate *priv;
14815
14816   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14817   g_return_if_fail (CLUTTER_IS_ACTION (action));
14818
14819   priv = self->priv;
14820
14821   if (priv->actions == NULL)
14822     {
14823       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14824       priv->actions->actor = self;
14825     }
14826
14827   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14828
14829   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14830 }
14831
14832 /**
14833  * clutter_actor_add_action_with_name:
14834  * @self: a #ClutterActor
14835  * @name: the name to set on the action
14836  * @action: a #ClutterAction
14837  *
14838  * A convenience function for setting the name of a #ClutterAction
14839  * while adding it to the list of actions applied to @self
14840  *
14841  * This function is the logical equivalent of:
14842  *
14843  * |[
14844  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14845  *   clutter_actor_add_action (self, action);
14846  * ]|
14847  *
14848  * Since: 1.4
14849  */
14850 void
14851 clutter_actor_add_action_with_name (ClutterActor  *self,
14852                                     const gchar   *name,
14853                                     ClutterAction *action)
14854 {
14855   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14856   g_return_if_fail (name != NULL);
14857   g_return_if_fail (CLUTTER_IS_ACTION (action));
14858
14859   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14860   clutter_actor_add_action (self, action);
14861 }
14862
14863 /**
14864  * clutter_actor_remove_action:
14865  * @self: a #ClutterActor
14866  * @action: a #ClutterAction
14867  *
14868  * Removes @action from the list of actions applied to @self
14869  *
14870  * The reference held by @self on the #ClutterAction will be released
14871  *
14872  * Since: 1.4
14873  */
14874 void
14875 clutter_actor_remove_action (ClutterActor  *self,
14876                              ClutterAction *action)
14877 {
14878   ClutterActorPrivate *priv;
14879
14880   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14881   g_return_if_fail (CLUTTER_IS_ACTION (action));
14882
14883   priv = self->priv;
14884
14885   if (priv->actions == NULL)
14886     return;
14887
14888   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14889
14890   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14891     g_clear_object (&priv->actions);
14892
14893   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14894 }
14895
14896 /**
14897  * clutter_actor_remove_action_by_name:
14898  * @self: a #ClutterActor
14899  * @name: the name of the action to remove
14900  *
14901  * Removes the #ClutterAction with the given name from the list
14902  * of actions applied to @self
14903  *
14904  * Since: 1.4
14905  */
14906 void
14907 clutter_actor_remove_action_by_name (ClutterActor *self,
14908                                      const gchar  *name)
14909 {
14910   ClutterActorPrivate *priv;
14911   ClutterActorMeta *meta;
14912
14913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14914   g_return_if_fail (name != NULL);
14915
14916   priv = self->priv;
14917
14918   if (priv->actions == NULL)
14919     return;
14920
14921   meta = _clutter_meta_group_get_meta (priv->actions, name);
14922   if (meta == NULL)
14923     return;
14924
14925   _clutter_meta_group_remove_meta (priv->actions, meta);
14926
14927   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14928 }
14929
14930 /**
14931  * clutter_actor_get_actions:
14932  * @self: a #ClutterActor
14933  *
14934  * Retrieves the list of actions applied to @self
14935  *
14936  * Return value: (transfer container) (element-type Clutter.Action): a copy
14937  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14938  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14939  *   allocated by the returned #GList
14940  *
14941  * Since: 1.4
14942  */
14943 GList *
14944 clutter_actor_get_actions (ClutterActor *self)
14945 {
14946   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14947
14948   if (self->priv->actions == NULL)
14949     return NULL;
14950
14951   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14952 }
14953
14954 /**
14955  * clutter_actor_get_action:
14956  * @self: a #ClutterActor
14957  * @name: the name of the action to retrieve
14958  *
14959  * Retrieves the #ClutterAction with the given name in the list
14960  * of actions applied to @self
14961  *
14962  * Return value: (transfer none): a #ClutterAction for the given
14963  *   name, or %NULL. The returned #ClutterAction is owned by the
14964  *   actor and it should not be unreferenced directly
14965  *
14966  * Since: 1.4
14967  */
14968 ClutterAction *
14969 clutter_actor_get_action (ClutterActor *self,
14970                           const gchar  *name)
14971 {
14972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14973   g_return_val_if_fail (name != NULL, NULL);
14974
14975   if (self->priv->actions == NULL)
14976     return NULL;
14977
14978   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14979 }
14980
14981 /**
14982  * clutter_actor_clear_actions:
14983  * @self: a #ClutterActor
14984  *
14985  * Clears the list of actions applied to @self
14986  *
14987  * Since: 1.4
14988  */
14989 void
14990 clutter_actor_clear_actions (ClutterActor *self)
14991 {
14992   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14993
14994   if (self->priv->actions == NULL)
14995     return;
14996
14997   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14998 }
14999
15000 /**
15001  * clutter_actor_add_constraint:
15002  * @self: a #ClutterActor
15003  * @constraint: a #ClutterConstraint
15004  *
15005  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15006  * to @self
15007  *
15008  * The #ClutterActor will hold a reference on the @constraint until
15009  * either clutter_actor_remove_constraint() or
15010  * clutter_actor_clear_constraints() is called.
15011  *
15012  * Since: 1.4
15013  */
15014 void
15015 clutter_actor_add_constraint (ClutterActor      *self,
15016                               ClutterConstraint *constraint)
15017 {
15018   ClutterActorPrivate *priv;
15019
15020   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15021   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15022
15023   priv = self->priv;
15024
15025   if (priv->constraints == NULL)
15026     {
15027       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15028       priv->constraints->actor = self;
15029     }
15030
15031   _clutter_meta_group_add_meta (priv->constraints,
15032                                 CLUTTER_ACTOR_META (constraint));
15033   clutter_actor_queue_relayout (self);
15034
15035   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15036 }
15037
15038 /**
15039  * clutter_actor_add_constraint_with_name:
15040  * @self: a #ClutterActor
15041  * @name: the name to set on the constraint
15042  * @constraint: a #ClutterConstraint
15043  *
15044  * A convenience function for setting the name of a #ClutterConstraint
15045  * while adding it to the list of constraints applied to @self
15046  *
15047  * This function is the logical equivalent of:
15048  *
15049  * |[
15050  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15051  *   clutter_actor_add_constraint (self, constraint);
15052  * ]|
15053  *
15054  * Since: 1.4
15055  */
15056 void
15057 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15058                                         const gchar       *name,
15059                                         ClutterConstraint *constraint)
15060 {
15061   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15062   g_return_if_fail (name != NULL);
15063   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15064
15065   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15066   clutter_actor_add_constraint (self, constraint);
15067 }
15068
15069 /**
15070  * clutter_actor_remove_constraint:
15071  * @self: a #ClutterActor
15072  * @constraint: a #ClutterConstraint
15073  *
15074  * Removes @constraint from the list of constraints applied to @self
15075  *
15076  * The reference held by @self on the #ClutterConstraint will be released
15077  *
15078  * Since: 1.4
15079  */
15080 void
15081 clutter_actor_remove_constraint (ClutterActor      *self,
15082                                  ClutterConstraint *constraint)
15083 {
15084   ClutterActorPrivate *priv;
15085
15086   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15087   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15088
15089   priv = self->priv;
15090
15091   if (priv->constraints == NULL)
15092     return;
15093
15094   _clutter_meta_group_remove_meta (priv->constraints,
15095                                    CLUTTER_ACTOR_META (constraint));
15096
15097   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15098     g_clear_object (&priv->constraints);
15099
15100   clutter_actor_queue_relayout (self);
15101
15102   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15103 }
15104
15105 /**
15106  * clutter_actor_remove_constraint_by_name:
15107  * @self: a #ClutterActor
15108  * @name: the name of the constraint to remove
15109  *
15110  * Removes the #ClutterConstraint with the given name from the list
15111  * of constraints applied to @self
15112  *
15113  * Since: 1.4
15114  */
15115 void
15116 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15117                                          const gchar  *name)
15118 {
15119   ClutterActorPrivate *priv;
15120   ClutterActorMeta *meta;
15121
15122   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15123   g_return_if_fail (name != NULL);
15124
15125   priv = self->priv;
15126
15127   if (priv->constraints == NULL)
15128     return;
15129
15130   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15131   if (meta == NULL)
15132     return;
15133
15134   _clutter_meta_group_remove_meta (priv->constraints, meta);
15135   clutter_actor_queue_relayout (self);
15136 }
15137
15138 /**
15139  * clutter_actor_get_constraints:
15140  * @self: a #ClutterActor
15141  *
15142  * Retrieves the list of constraints applied to @self
15143  *
15144  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15145  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15146  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15147  *   allocated by the returned #GList
15148  *
15149  * Since: 1.4
15150  */
15151 GList *
15152 clutter_actor_get_constraints (ClutterActor *self)
15153 {
15154   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15155
15156   if (self->priv->constraints == NULL)
15157     return NULL;
15158
15159   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15160 }
15161
15162 /**
15163  * clutter_actor_get_constraint:
15164  * @self: a #ClutterActor
15165  * @name: the name of the constraint to retrieve
15166  *
15167  * Retrieves the #ClutterConstraint with the given name in the list
15168  * of constraints applied to @self
15169  *
15170  * Return value: (transfer none): a #ClutterConstraint for the given
15171  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15172  *   actor and it should not be unreferenced directly
15173  *
15174  * Since: 1.4
15175  */
15176 ClutterConstraint *
15177 clutter_actor_get_constraint (ClutterActor *self,
15178                               const gchar  *name)
15179 {
15180   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15181   g_return_val_if_fail (name != NULL, NULL);
15182
15183   if (self->priv->constraints == NULL)
15184     return NULL;
15185
15186   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15187 }
15188
15189 /**
15190  * clutter_actor_clear_constraints:
15191  * @self: a #ClutterActor
15192  *
15193  * Clears the list of constraints applied to @self
15194  *
15195  * Since: 1.4
15196  */
15197 void
15198 clutter_actor_clear_constraints (ClutterActor *self)
15199 {
15200   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15201
15202   if (self->priv->constraints == NULL)
15203     return;
15204
15205   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15206
15207   clutter_actor_queue_relayout (self);
15208 }
15209
15210 /**
15211  * clutter_actor_set_clip_to_allocation:
15212  * @self: a #ClutterActor
15213  * @clip_set: %TRUE to apply a clip tracking the allocation
15214  *
15215  * Sets whether @self should be clipped to the same size as its
15216  * allocation
15217  *
15218  * Since: 1.4
15219  */
15220 void
15221 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15222                                       gboolean      clip_set)
15223 {
15224   ClutterActorPrivate *priv;
15225
15226   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15227
15228   clip_set = !!clip_set;
15229
15230   priv = self->priv;
15231
15232   if (priv->clip_to_allocation != clip_set)
15233     {
15234       priv->clip_to_allocation = clip_set;
15235
15236       clutter_actor_queue_redraw (self);
15237
15238       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15239     }
15240 }
15241
15242 /**
15243  * clutter_actor_get_clip_to_allocation:
15244  * @self: a #ClutterActor
15245  *
15246  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15247  *
15248  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15249  *
15250  * Since: 1.4
15251  */
15252 gboolean
15253 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15254 {
15255   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15256
15257   return self->priv->clip_to_allocation;
15258 }
15259
15260 /**
15261  * clutter_actor_add_effect:
15262  * @self: a #ClutterActor
15263  * @effect: a #ClutterEffect
15264  *
15265  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15266  *
15267  * The #ClutterActor will hold a reference on the @effect until either
15268  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15269  * called.
15270  *
15271  * Since: 1.4
15272  */
15273 void
15274 clutter_actor_add_effect (ClutterActor  *self,
15275                           ClutterEffect *effect)
15276 {
15277   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15278   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15279
15280   _clutter_actor_add_effect_internal (self, effect);
15281
15282   clutter_actor_queue_redraw (self);
15283
15284   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15285 }
15286
15287 /**
15288  * clutter_actor_add_effect_with_name:
15289  * @self: a #ClutterActor
15290  * @name: the name to set on the effect
15291  * @effect: a #ClutterEffect
15292  *
15293  * A convenience function for setting the name of a #ClutterEffect
15294  * while adding it to the list of effectss applied to @self
15295  *
15296  * This function is the logical equivalent of:
15297  *
15298  * |[
15299  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15300  *   clutter_actor_add_effect (self, effect);
15301  * ]|
15302  *
15303  * Since: 1.4
15304  */
15305 void
15306 clutter_actor_add_effect_with_name (ClutterActor  *self,
15307                                     const gchar   *name,
15308                                     ClutterEffect *effect)
15309 {
15310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15311   g_return_if_fail (name != NULL);
15312   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15313
15314   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15315   clutter_actor_add_effect (self, effect);
15316 }
15317
15318 /**
15319  * clutter_actor_remove_effect:
15320  * @self: a #ClutterActor
15321  * @effect: a #ClutterEffect
15322  *
15323  * Removes @effect from the list of effects applied to @self
15324  *
15325  * The reference held by @self on the #ClutterEffect will be released
15326  *
15327  * Since: 1.4
15328  */
15329 void
15330 clutter_actor_remove_effect (ClutterActor  *self,
15331                              ClutterEffect *effect)
15332 {
15333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15334   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15335
15336   _clutter_actor_remove_effect_internal (self, effect);
15337
15338   clutter_actor_queue_redraw (self);
15339
15340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15341 }
15342
15343 /**
15344  * clutter_actor_remove_effect_by_name:
15345  * @self: a #ClutterActor
15346  * @name: the name of the effect to remove
15347  *
15348  * Removes the #ClutterEffect with the given name from the list
15349  * of effects applied to @self
15350  *
15351  * Since: 1.4
15352  */
15353 void
15354 clutter_actor_remove_effect_by_name (ClutterActor *self,
15355                                      const gchar  *name)
15356 {
15357   ClutterActorPrivate *priv;
15358   ClutterActorMeta *meta;
15359
15360   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15361   g_return_if_fail (name != NULL);
15362
15363   priv = self->priv;
15364
15365   if (priv->effects == NULL)
15366     return;
15367
15368   meta = _clutter_meta_group_get_meta (priv->effects, name);
15369   if (meta == NULL)
15370     return;
15371
15372   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15373 }
15374
15375 /**
15376  * clutter_actor_get_effects:
15377  * @self: a #ClutterActor
15378  *
15379  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15380  *
15381  * Return value: (transfer container) (element-type Clutter.Effect): a list
15382  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15383  *   list are owned by Clutter and they should not be freed. You should
15384  *   free the returned list using g_list_free() when done
15385  *
15386  * Since: 1.4
15387  */
15388 GList *
15389 clutter_actor_get_effects (ClutterActor *self)
15390 {
15391   ClutterActorPrivate *priv;
15392
15393   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15394
15395   priv = self->priv;
15396
15397   if (priv->effects == NULL)
15398     return NULL;
15399
15400   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15401 }
15402
15403 /**
15404  * clutter_actor_get_effect:
15405  * @self: a #ClutterActor
15406  * @name: the name of the effect to retrieve
15407  *
15408  * Retrieves the #ClutterEffect with the given name in the list
15409  * of effects applied to @self
15410  *
15411  * Return value: (transfer none): a #ClutterEffect for the given
15412  *   name, or %NULL. The returned #ClutterEffect is owned by the
15413  *   actor and it should not be unreferenced directly
15414  *
15415  * Since: 1.4
15416  */
15417 ClutterEffect *
15418 clutter_actor_get_effect (ClutterActor *self,
15419                           const gchar  *name)
15420 {
15421   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15422   g_return_val_if_fail (name != NULL, NULL);
15423
15424   if (self->priv->effects == NULL)
15425     return NULL;
15426
15427   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15428 }
15429
15430 /**
15431  * clutter_actor_clear_effects:
15432  * @self: a #ClutterActor
15433  *
15434  * Clears the list of effects applied to @self
15435  *
15436  * Since: 1.4
15437  */
15438 void
15439 clutter_actor_clear_effects (ClutterActor *self)
15440 {
15441   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15442
15443   if (self->priv->effects == NULL)
15444     return;
15445
15446   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15447
15448   clutter_actor_queue_redraw (self);
15449 }
15450
15451 /**
15452  * clutter_actor_has_key_focus:
15453  * @self: a #ClutterActor
15454  *
15455  * Checks whether @self is the #ClutterActor that has key focus
15456  *
15457  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15458  *
15459  * Since: 1.4
15460  */
15461 gboolean
15462 clutter_actor_has_key_focus (ClutterActor *self)
15463 {
15464   ClutterActor *stage;
15465
15466   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15467
15468   stage = _clutter_actor_get_stage_internal (self);
15469   if (stage == NULL)
15470     return FALSE;
15471
15472   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15473 }
15474
15475 static gboolean
15476 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15477                                       ClutterPaintVolume *pv)
15478 {
15479   ClutterActorPrivate *priv = self->priv;
15480
15481   /* Actors are only expected to report a valid paint volume
15482    * while they have a valid allocation. */
15483   if (G_UNLIKELY (priv->needs_allocation))
15484     {
15485       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15486                     "Actor needs allocation",
15487                     _clutter_actor_get_debug_name (self));
15488       return FALSE;
15489     }
15490
15491   /* Check if there are any handlers connected to the paint
15492    * signal. If there are then all bets are off for what the paint
15493    * volume for this actor might possibly be!
15494    *
15495    * XXX: It's expected that this is going to end up being quite a
15496    * costly check to have to do here, but we haven't come up with
15497    * another solution that can reliably catch paint signal handlers at
15498    * the right time to either avoid artefacts due to invalid stage
15499    * clipping or due to incorrect culling.
15500    *
15501    * Previously we checked in clutter_actor_paint(), but at that time
15502    * we may already be using a stage clip that could be derived from
15503    * an invalid paint-volume. We used to try and handle that by
15504    * queuing a follow up, unclipped, redraw but still the previous
15505    * checking wasn't enough to catch invalid volumes involved in
15506    * culling (considering that containers may derive their volume from
15507    * children that haven't yet been painted)
15508    *
15509    * Longer term, improved solutions could be:
15510    * - Disallow painting in the paint signal, only allow using it
15511    *   for tracking when paints happen. We can add another API that
15512    *   allows monkey patching the paint of arbitrary actors but in a
15513    *   more controlled way and that also supports modifying the
15514    *   paint-volume.
15515    * - If we could be notified somehow when signal handlers are
15516    *   connected we wouldn't have to poll for handlers like this.
15517    */
15518   if (g_signal_has_handler_pending (self,
15519                                     actor_signals[PAINT],
15520                                     0,
15521                                     TRUE))
15522     {
15523       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15524                     "Actor has \"paint\" signal handlers",
15525                     _clutter_actor_get_debug_name (self));
15526       return FALSE;
15527     }
15528
15529   _clutter_paint_volume_init_static (pv, self);
15530
15531   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15532     {
15533       clutter_paint_volume_free (pv);
15534       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15535                     "Actor failed to report a volume",
15536                     _clutter_actor_get_debug_name (self));
15537       return FALSE;
15538     }
15539
15540   /* since effects can modify the paint volume, we allow them to actually
15541    * do this by making get_paint_volume() "context sensitive"
15542    */
15543   if (priv->effects != NULL)
15544     {
15545       if (priv->current_effect != NULL)
15546         {
15547           const GList *effects, *l;
15548
15549           /* if we are being called from within the paint sequence of
15550            * an actor, get the paint volume up to the current effect
15551            */
15552           effects = _clutter_meta_group_peek_metas (priv->effects);
15553           for (l = effects;
15554                l != NULL || (l != NULL && l->data != priv->current_effect);
15555                l = l->next)
15556             {
15557               if (!_clutter_effect_get_paint_volume (l->data, pv))
15558                 {
15559                   clutter_paint_volume_free (pv);
15560                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15561                                 "Effect (%s) failed to report a volume",
15562                                 _clutter_actor_get_debug_name (self),
15563                                 _clutter_actor_meta_get_debug_name (l->data));
15564                   return FALSE;
15565                 }
15566             }
15567         }
15568       else
15569         {
15570           const GList *effects, *l;
15571
15572           /* otherwise, get the cumulative volume */
15573           effects = _clutter_meta_group_peek_metas (priv->effects);
15574           for (l = effects; l != NULL; l = l->next)
15575             if (!_clutter_effect_get_paint_volume (l->data, pv))
15576               {
15577                 clutter_paint_volume_free (pv);
15578                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15579                               "Effect (%s) failed to report a volume",
15580                               _clutter_actor_get_debug_name (self),
15581                               _clutter_actor_meta_get_debug_name (l->data));
15582                 return FALSE;
15583               }
15584         }
15585     }
15586
15587   return TRUE;
15588 }
15589
15590 /* The public clutter_actor_get_paint_volume API returns a const
15591  * pointer since we return a pointer directly to the cached
15592  * PaintVolume associated with the actor and don't want the user to
15593  * inadvertently modify it, but for internal uses we sometimes need
15594  * access to the same PaintVolume but need to apply some book-keeping
15595  * modifications to it so we don't want a const pointer.
15596  */
15597 static ClutterPaintVolume *
15598 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15599 {
15600   ClutterActorPrivate *priv;
15601
15602   priv = self->priv;
15603
15604   if (priv->paint_volume_valid)
15605     clutter_paint_volume_free (&priv->paint_volume);
15606
15607   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15608     {
15609       priv->paint_volume_valid = TRUE;
15610       return &priv->paint_volume;
15611     }
15612   else
15613     {
15614       priv->paint_volume_valid = FALSE;
15615       return NULL;
15616     }
15617 }
15618
15619 /**
15620  * clutter_actor_get_paint_volume:
15621  * @self: a #ClutterActor
15622  *
15623  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15624  * when a paint volume can't be determined.
15625  *
15626  * The paint volume is defined as the 3D space occupied by an actor
15627  * when being painted.
15628  *
15629  * This function will call the <function>get_paint_volume()</function>
15630  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15631  * should not usually care about overriding the default implementation,
15632  * unless they are, for instance: painting outside their allocation, or
15633  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15634  * 3D depth).
15635  *
15636  * <note>2D actors overriding <function>get_paint_volume()</function>
15637  * ensure their volume has a depth of 0. (This will be true so long as
15638  * you don't call clutter_paint_volume_set_depth().)</note>
15639  *
15640  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15641  *   or %NULL if no volume could be determined. The returned pointer
15642  *   is not guaranteed to be valid across multiple frames; if you want
15643  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15644  *
15645  * Since: 1.6
15646  */
15647 const ClutterPaintVolume *
15648 clutter_actor_get_paint_volume (ClutterActor *self)
15649 {
15650   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15651
15652   return _clutter_actor_get_paint_volume_mutable (self);
15653 }
15654
15655 /**
15656  * clutter_actor_get_transformed_paint_volume:
15657  * @self: a #ClutterActor
15658  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15659  *    (or %NULL for the stage)
15660  *
15661  * Retrieves the 3D paint volume of an actor like
15662  * clutter_actor_get_paint_volume() does (Please refer to the
15663  * documentation of clutter_actor_get_paint_volume() for more
15664  * details.) and it additionally transforms the paint volume into the
15665  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15666  * is passed for @relative_to_ancestor)
15667  *
15668  * This can be used by containers that base their paint volume on
15669  * the volume of their children. Such containers can query the
15670  * transformed paint volume of all of its children and union them
15671  * together using clutter_paint_volume_union().
15672  *
15673  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15674  *   or %NULL if no volume could be determined. The returned pointer is
15675  *   not guaranteed to be valid across multiple frames; if you wish to
15676  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15677  *
15678  * Since: 1.6
15679  */
15680 const ClutterPaintVolume *
15681 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15682                                             ClutterActor *relative_to_ancestor)
15683 {
15684   const ClutterPaintVolume *volume;
15685   ClutterActor *stage;
15686   ClutterPaintVolume *transformed_volume;
15687
15688   stage = _clutter_actor_get_stage_internal (self);
15689   if (G_UNLIKELY (stage == NULL))
15690     return NULL;
15691
15692   if (relative_to_ancestor == NULL)
15693     relative_to_ancestor = stage;
15694
15695   volume = clutter_actor_get_paint_volume (self);
15696   if (volume == NULL)
15697     return NULL;
15698
15699   transformed_volume =
15700     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15701
15702   _clutter_paint_volume_copy_static (volume, transformed_volume);
15703
15704   _clutter_paint_volume_transform_relative (transformed_volume,
15705                                             relative_to_ancestor);
15706
15707   return transformed_volume;
15708 }
15709
15710 /**
15711  * clutter_actor_get_paint_box:
15712  * @self: a #ClutterActor
15713  * @box: (out): return location for a #ClutterActorBox
15714  *
15715  * Retrieves the paint volume of the passed #ClutterActor, and
15716  * transforms it into a 2D bounding box in stage coordinates.
15717  *
15718  * This function is useful to determine the on screen area occupied by
15719  * the actor. The box is only an approximation and may often be
15720  * considerably larger due to the optimizations used to calculate the
15721  * box. The box is never smaller though, so it can reliably be used
15722  * for culling.
15723  *
15724  * There are times when a 2D paint box can't be determined, e.g.
15725  * because the actor isn't yet parented under a stage or because
15726  * the actor is unable to determine a paint volume.
15727  *
15728  * Return value: %TRUE if a 2D paint box could be determined, else
15729  * %FALSE.
15730  *
15731  * Since: 1.6
15732  */
15733 gboolean
15734 clutter_actor_get_paint_box (ClutterActor    *self,
15735                              ClutterActorBox *box)
15736 {
15737   ClutterActor *stage;
15738   ClutterPaintVolume *pv;
15739
15740   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15741   g_return_val_if_fail (box != NULL, FALSE);
15742
15743   stage = _clutter_actor_get_stage_internal (self);
15744   if (G_UNLIKELY (!stage))
15745     return FALSE;
15746
15747   pv = _clutter_actor_get_paint_volume_mutable (self);
15748   if (G_UNLIKELY (!pv))
15749     return FALSE;
15750
15751   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15752
15753   return TRUE;
15754 }
15755
15756 /**
15757  * clutter_actor_has_overlaps:
15758  * @self: A #ClutterActor
15759  *
15760  * Asks the actor's implementation whether it may contain overlapping
15761  * primitives.
15762  *
15763  * For example; Clutter may use this to determine whether the painting
15764  * should be redirected to an offscreen buffer to correctly implement
15765  * the opacity property.
15766  *
15767  * Custom actors can override the default response by implementing the
15768  * #ClutterActor <function>has_overlaps</function> virtual function. See
15769  * clutter_actor_set_offscreen_redirect() for more information.
15770  *
15771  * Return value: %TRUE if the actor may have overlapping primitives, and
15772  *   %FALSE otherwise
15773  *
15774  * Since: 1.8
15775  */
15776 gboolean
15777 clutter_actor_has_overlaps (ClutterActor *self)
15778 {
15779   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15780
15781   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15782 }
15783
15784 /**
15785  * clutter_actor_has_effects:
15786  * @self: A #ClutterActor
15787  *
15788  * Returns whether the actor has any effects applied.
15789  *
15790  * Return value: %TRUE if the actor has any effects,
15791  *   %FALSE otherwise
15792  *
15793  * Since: 1.10
15794  */
15795 gboolean
15796 clutter_actor_has_effects (ClutterActor *self)
15797 {
15798   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15799
15800   if (self->priv->effects == NULL)
15801     return FALSE;
15802
15803   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15804 }
15805
15806 /**
15807  * clutter_actor_has_constraints:
15808  * @self: A #ClutterActor
15809  *
15810  * Returns whether the actor has any constraints applied.
15811  *
15812  * Return value: %TRUE if the actor has any constraints,
15813  *   %FALSE otherwise
15814  *
15815  * Since: 1.10
15816  */
15817 gboolean
15818 clutter_actor_has_constraints (ClutterActor *self)
15819 {
15820   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15821
15822   return self->priv->constraints != NULL;
15823 }
15824
15825 /**
15826  * clutter_actor_has_actions:
15827  * @self: A #ClutterActor
15828  *
15829  * Returns whether the actor has any actions applied.
15830  *
15831  * Return value: %TRUE if the actor has any actions,
15832  *   %FALSE otherwise
15833  *
15834  * Since: 1.10
15835  */
15836 gboolean
15837 clutter_actor_has_actions (ClutterActor *self)
15838 {
15839   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15840
15841   return self->priv->actions != NULL;
15842 }
15843
15844 /**
15845  * clutter_actor_get_n_children:
15846  * @self: a #ClutterActor
15847  *
15848  * Retrieves the number of children of @self.
15849  *
15850  * Return value: the number of children of an actor
15851  *
15852  * Since: 1.10
15853  */
15854 gint
15855 clutter_actor_get_n_children (ClutterActor *self)
15856 {
15857   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15858
15859   return self->priv->n_children;
15860 }
15861
15862 /**
15863  * clutter_actor_get_child_at_index:
15864  * @self: a #ClutterActor
15865  * @index_: the position in the list of children
15866  *
15867  * Retrieves the actor at the given @index_ inside the list of
15868  * children of @self.
15869  *
15870  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15871  *
15872  * Since: 1.10
15873  */
15874 ClutterActor *
15875 clutter_actor_get_child_at_index (ClutterActor *self,
15876                                   gint          index_)
15877 {
15878   ClutterActor *iter;
15879   int i;
15880
15881   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15882   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15883
15884   for (iter = self->priv->first_child, i = 0;
15885        iter != NULL && i < index_;
15886        iter = iter->priv->next_sibling, i += 1)
15887     ;
15888
15889   return iter;
15890 }
15891
15892 /*< private >
15893  * _clutter_actor_foreach_child:
15894  * @actor: The actor whos children you want to iterate
15895  * @callback: The function to call for each child
15896  * @user_data: Private data to pass to @callback
15897  *
15898  * Calls a given @callback once for each child of the specified @actor and
15899  * passing the @user_data pointer each time.
15900  *
15901  * Return value: returns %TRUE if all children were iterated, else
15902  *    %FALSE if a callback broke out of iteration early.
15903  */
15904 gboolean
15905 _clutter_actor_foreach_child (ClutterActor           *self,
15906                               ClutterForeachCallback  callback,
15907                               gpointer                user_data)
15908 {
15909   ClutterActor *iter;
15910   gboolean cont;
15911
15912   if (self->priv->first_child == NULL)
15913     return TRUE;
15914
15915   cont = TRUE;
15916   iter = self->priv->first_child;
15917
15918   /* we use this form so that it's safe to change the children
15919    * list while iterating it
15920    */
15921   while (cont && iter != NULL)
15922     {
15923       ClutterActor *next = iter->priv->next_sibling;
15924
15925       cont = callback (iter, user_data);
15926
15927       iter = next;
15928     }
15929
15930   return cont;
15931 }
15932
15933 #if 0
15934 /* For debugging purposes this gives us a simple way to print out
15935  * the scenegraph e.g in gdb using:
15936  * [|
15937  *   _clutter_actor_traverse (stage,
15938  *                            0,
15939  *                            clutter_debug_print_actor_cb,
15940  *                            NULL,
15941  *                            NULL);
15942  * |]
15943  */
15944 static ClutterActorTraverseVisitFlags
15945 clutter_debug_print_actor_cb (ClutterActor *actor,
15946                               int depth,
15947                               void *user_data)
15948 {
15949   g_print ("%*s%s:%p\n",
15950            depth * 2, "",
15951            _clutter_actor_get_debug_name (actor),
15952            actor);
15953
15954   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15955 }
15956 #endif
15957
15958 static void
15959 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15960                                  ClutterTraverseCallback callback,
15961                                  gpointer                user_data)
15962 {
15963   GQueue *queue = g_queue_new ();
15964   ClutterActor dummy;
15965   int current_depth = 0;
15966
15967   g_queue_push_tail (queue, actor);
15968   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15969
15970   while ((actor = g_queue_pop_head (queue)))
15971     {
15972       ClutterActorTraverseVisitFlags flags;
15973
15974       if (actor == &dummy)
15975         {
15976           current_depth++;
15977           g_queue_push_tail (queue, &dummy);
15978           continue;
15979         }
15980
15981       flags = callback (actor, current_depth, user_data);
15982       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15983         break;
15984       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15985         {
15986           ClutterActor *iter;
15987
15988           for (iter = actor->priv->first_child;
15989                iter != NULL;
15990                iter = iter->priv->next_sibling)
15991             {
15992               g_queue_push_tail (queue, iter);
15993             }
15994         }
15995     }
15996
15997   g_queue_free (queue);
15998 }
15999
16000 static ClutterActorTraverseVisitFlags
16001 _clutter_actor_traverse_depth (ClutterActor           *actor,
16002                                ClutterTraverseCallback before_children_callback,
16003                                ClutterTraverseCallback after_children_callback,
16004                                int                     current_depth,
16005                                gpointer                user_data)
16006 {
16007   ClutterActorTraverseVisitFlags flags;
16008
16009   flags = before_children_callback (actor, current_depth, user_data);
16010   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16011     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16012
16013   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16014     {
16015       ClutterActor *iter;
16016
16017       for (iter = actor->priv->first_child;
16018            iter != NULL;
16019            iter = iter->priv->next_sibling)
16020         {
16021           flags = _clutter_actor_traverse_depth (iter,
16022                                                  before_children_callback,
16023                                                  after_children_callback,
16024                                                  current_depth + 1,
16025                                                  user_data);
16026
16027           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16028             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16029         }
16030     }
16031
16032   if (after_children_callback)
16033     return after_children_callback (actor, current_depth, user_data);
16034   else
16035     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16036 }
16037
16038 /* _clutter_actor_traverse:
16039  * @actor: The actor to start traversing the graph from
16040  * @flags: These flags may affect how the traversal is done
16041  * @before_children_callback: A function to call before visiting the
16042  *   children of the current actor.
16043  * @after_children_callback: A function to call after visiting the
16044  *   children of the current actor. (Ignored if
16045  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16046  * @user_data: The private data to pass to the callbacks
16047  *
16048  * Traverses the scenegraph starting at the specified @actor and
16049  * descending through all its children and its children's children.
16050  * For each actor traversed @before_children_callback and
16051  * @after_children_callback are called with the specified
16052  * @user_data, before and after visiting that actor's children.
16053  *
16054  * The callbacks can return flags that affect the ongoing traversal
16055  * such as by skipping over an actors children or bailing out of
16056  * any further traversing.
16057  */
16058 void
16059 _clutter_actor_traverse (ClutterActor              *actor,
16060                          ClutterActorTraverseFlags  flags,
16061                          ClutterTraverseCallback    before_children_callback,
16062                          ClutterTraverseCallback    after_children_callback,
16063                          gpointer                   user_data)
16064 {
16065   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16066     _clutter_actor_traverse_breadth (actor,
16067                                      before_children_callback,
16068                                      user_data);
16069   else /* DEPTH_FIRST */
16070     _clutter_actor_traverse_depth (actor,
16071                                    before_children_callback,
16072                                    after_children_callback,
16073                                    0, /* start depth */
16074                                    user_data);
16075 }
16076
16077 static void
16078 on_layout_manager_changed (ClutterLayoutManager *manager,
16079                            ClutterActor         *self)
16080 {
16081   clutter_actor_queue_relayout (self);
16082 }
16083
16084 /**
16085  * clutter_actor_set_layout_manager:
16086  * @self: a #ClutterActor
16087  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16088  *
16089  * Sets the #ClutterLayoutManager delegate object that will be used to
16090  * lay out the children of @self.
16091  *
16092  * The #ClutterActor will take a reference on the passed @manager which
16093  * will be released either when the layout manager is removed, or when
16094  * the actor is destroyed.
16095  *
16096  * Since: 1.10
16097  */
16098 void
16099 clutter_actor_set_layout_manager (ClutterActor         *self,
16100                                   ClutterLayoutManager *manager)
16101 {
16102   ClutterActorPrivate *priv;
16103
16104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16105   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16106
16107   priv = self->priv;
16108
16109   if (priv->layout_manager != NULL)
16110     {
16111       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16112                                             G_CALLBACK (on_layout_manager_changed),
16113                                             self);
16114       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16115       g_clear_object (&priv->layout_manager);
16116     }
16117
16118   priv->layout_manager = manager;
16119
16120   if (priv->layout_manager != NULL)
16121     {
16122       g_object_ref_sink (priv->layout_manager);
16123       clutter_layout_manager_set_container (priv->layout_manager,
16124                                             CLUTTER_CONTAINER (self));
16125       g_signal_connect (priv->layout_manager, "layout-changed",
16126                         G_CALLBACK (on_layout_manager_changed),
16127                         self);
16128     }
16129
16130   clutter_actor_queue_relayout (self);
16131
16132   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16133 }
16134
16135 /**
16136  * clutter_actor_get_layout_manager:
16137  * @self: a #ClutterActor
16138  *
16139  * Retrieves the #ClutterLayoutManager used by @self.
16140  *
16141  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16142  *   or %NULL
16143  *
16144  * Since: 1.10
16145  */
16146 ClutterLayoutManager *
16147 clutter_actor_get_layout_manager (ClutterActor *self)
16148 {
16149   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16150
16151   return self->priv->layout_manager;
16152 }
16153
16154 static const ClutterLayoutInfo default_layout_info = {
16155   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16156   { 0, 0, 0, 0 },               /* margin */
16157   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16158   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16159   FALSE, FALSE,                 /* expand */
16160   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16161   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16162 };
16163
16164 static void
16165 layout_info_free (gpointer data)
16166 {
16167   if (G_LIKELY (data != NULL))
16168     g_slice_free (ClutterLayoutInfo, data);
16169 }
16170
16171 /*< private >
16172  * _clutter_actor_get_layout_info:
16173  * @self: a #ClutterActor
16174  *
16175  * Retrieves a pointer to the ClutterLayoutInfo structure.
16176  *
16177  * If the actor does not have a ClutterLayoutInfo associated to it, one
16178  * will be created and initialized to the default values.
16179  *
16180  * This function should be used for setters.
16181  *
16182  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16183  * instead.
16184  *
16185  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16186  */
16187 ClutterLayoutInfo *
16188 _clutter_actor_get_layout_info (ClutterActor *self)
16189 {
16190   ClutterLayoutInfo *retval;
16191
16192   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16193   if (retval == NULL)
16194     {
16195       retval = g_slice_new (ClutterLayoutInfo);
16196
16197       *retval = default_layout_info;
16198
16199       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16200                                retval,
16201                                layout_info_free);
16202     }
16203
16204   return retval;
16205 }
16206
16207 /*< private >
16208  * _clutter_actor_get_layout_info_or_defaults:
16209  * @self: a #ClutterActor
16210  *
16211  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16212  *
16213  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16214  * then the default structure will be returned.
16215  *
16216  * This function should only be used for getters.
16217  *
16218  * Return value: a const pointer to the ClutterLayoutInfo structure
16219  */
16220 const ClutterLayoutInfo *
16221 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16222 {
16223   const ClutterLayoutInfo *info;
16224
16225   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16226   if (info == NULL)
16227     return &default_layout_info;
16228
16229   return info;
16230 }
16231
16232 /**
16233  * clutter_actor_set_x_align:
16234  * @self: a #ClutterActor
16235  * @x_align: the horizontal alignment policy
16236  *
16237  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16238  * actor received extra horizontal space.
16239  *
16240  * See also the #ClutterActor:x-align property.
16241  *
16242  * Since: 1.10
16243  */
16244 void
16245 clutter_actor_set_x_align (ClutterActor      *self,
16246                            ClutterActorAlign  x_align)
16247 {
16248   ClutterLayoutInfo *info;
16249
16250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16251
16252   info = _clutter_actor_get_layout_info (self);
16253
16254   if (info->x_align != x_align)
16255     {
16256       info->x_align = x_align;
16257
16258       clutter_actor_queue_relayout (self);
16259
16260       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16261     }
16262 }
16263
16264 /**
16265  * clutter_actor_get_x_align:
16266  * @self: a #ClutterActor
16267  *
16268  * Retrieves the horizontal alignment policy set using
16269  * clutter_actor_set_x_align().
16270  *
16271  * Return value: the horizontal alignment policy.
16272  *
16273  * Since: 1.10
16274  */
16275 ClutterActorAlign
16276 clutter_actor_get_x_align (ClutterActor *self)
16277 {
16278   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16279
16280   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16281 }
16282
16283 /**
16284  * clutter_actor_set_y_align:
16285  * @self: a #ClutterActor
16286  * @y_align: the vertical alignment policy
16287  *
16288  * Sets the vertical alignment policy of a #ClutterActor, in case the
16289  * actor received extra vertical space.
16290  *
16291  * See also the #ClutterActor:y-align property.
16292  *
16293  * Since: 1.10
16294  */
16295 void
16296 clutter_actor_set_y_align (ClutterActor      *self,
16297                            ClutterActorAlign  y_align)
16298 {
16299   ClutterLayoutInfo *info;
16300
16301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16302
16303   info = _clutter_actor_get_layout_info (self);
16304
16305   if (info->y_align != y_align)
16306     {
16307       info->y_align = y_align;
16308
16309       clutter_actor_queue_relayout (self);
16310
16311       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16312     }
16313 }
16314
16315 /**
16316  * clutter_actor_get_y_align:
16317  * @self: a #ClutterActor
16318  *
16319  * Retrieves the vertical alignment policy set using
16320  * clutter_actor_set_y_align().
16321  *
16322  * Return value: the vertical alignment policy.
16323  *
16324  * Since: 1.10
16325  */
16326 ClutterActorAlign
16327 clutter_actor_get_y_align (ClutterActor *self)
16328 {
16329   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16330
16331   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16332 }
16333
16334 /**
16335  * clutter_actor_set_margin:
16336  * @self: a #ClutterActor
16337  * @margin: a #ClutterMargin
16338  *
16339  * Sets all the components of the margin of a #ClutterActor.
16340  *
16341  * Since: 1.10
16342  */
16343 void
16344 clutter_actor_set_margin (ClutterActor        *self,
16345                           const ClutterMargin *margin)
16346 {
16347   ClutterLayoutInfo *info;
16348   gboolean changed;
16349   GObject *obj;
16350
16351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16352   g_return_if_fail (margin != NULL);
16353
16354   obj = G_OBJECT (self);
16355   changed = FALSE;
16356
16357   g_object_freeze_notify (obj);
16358
16359   info = _clutter_actor_get_layout_info (self);
16360
16361   if (info->margin.top != margin->top)
16362     {
16363       info->margin.top = margin->top;
16364       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16365       changed = TRUE;
16366     }
16367
16368   if (info->margin.right != margin->right)
16369     {
16370       info->margin.right = margin->right;
16371       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16372       changed = TRUE;
16373     }
16374
16375   if (info->margin.bottom != margin->bottom)
16376     {
16377       info->margin.bottom = margin->bottom;
16378       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16379       changed = TRUE;
16380     }
16381
16382   if (info->margin.left != margin->left)
16383     {
16384       info->margin.left = margin->left;
16385       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16386       changed = TRUE;
16387     }
16388
16389   if (changed)
16390     clutter_actor_queue_relayout (self);
16391
16392   g_object_thaw_notify (obj);
16393 }
16394
16395 /**
16396  * clutter_actor_get_margin:
16397  * @self: a #ClutterActor
16398  * @margin: (out caller-allocates): return location for a #ClutterMargin
16399  *
16400  * Retrieves all the components of the margin of a #ClutterActor.
16401  *
16402  * Since: 1.10
16403  */
16404 void
16405 clutter_actor_get_margin (ClutterActor  *self,
16406                           ClutterMargin *margin)
16407 {
16408   const ClutterLayoutInfo *info;
16409
16410   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16411   g_return_if_fail (margin != NULL);
16412
16413   info = _clutter_actor_get_layout_info_or_defaults (self);
16414
16415   *margin = info->margin;
16416 }
16417
16418 /**
16419  * clutter_actor_set_margin_top:
16420  * @self: a #ClutterActor
16421  * @margin: the top margin
16422  *
16423  * Sets the margin from the top of a #ClutterActor.
16424  *
16425  * Since: 1.10
16426  */
16427 void
16428 clutter_actor_set_margin_top (ClutterActor *self,
16429                               gfloat        margin)
16430 {
16431   ClutterLayoutInfo *info;
16432
16433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16434   g_return_if_fail (margin >= 0.f);
16435
16436   info = _clutter_actor_get_layout_info (self);
16437
16438   if (info->margin.top == margin)
16439     return;
16440
16441   info->margin.top = margin;
16442
16443   clutter_actor_queue_relayout (self);
16444
16445   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16446 }
16447
16448 /**
16449  * clutter_actor_get_margin_top:
16450  * @self: a #ClutterActor
16451  *
16452  * Retrieves the top margin of a #ClutterActor.
16453  *
16454  * Return value: the top margin
16455  *
16456  * Since: 1.10
16457  */
16458 gfloat
16459 clutter_actor_get_margin_top (ClutterActor *self)
16460 {
16461   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16462
16463   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16464 }
16465
16466 /**
16467  * clutter_actor_set_margin_bottom:
16468  * @self: a #ClutterActor
16469  * @margin: the bottom margin
16470  *
16471  * Sets the margin from the bottom of a #ClutterActor.
16472  *
16473  * Since: 1.10
16474  */
16475 void
16476 clutter_actor_set_margin_bottom (ClutterActor *self,
16477                                  gfloat        margin)
16478 {
16479   ClutterLayoutInfo *info;
16480
16481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16482   g_return_if_fail (margin >= 0.f);
16483
16484   info = _clutter_actor_get_layout_info (self);
16485
16486   if (info->margin.bottom == margin)
16487     return;
16488
16489   info->margin.bottom = margin;
16490
16491   clutter_actor_queue_relayout (self);
16492
16493   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16494 }
16495
16496 /**
16497  * clutter_actor_get_margin_bottom:
16498  * @self: a #ClutterActor
16499  *
16500  * Retrieves the bottom margin of a #ClutterActor.
16501  *
16502  * Return value: the bottom margin
16503  *
16504  * Since: 1.10
16505  */
16506 gfloat
16507 clutter_actor_get_margin_bottom (ClutterActor *self)
16508 {
16509   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16510
16511   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16512 }
16513
16514 /**
16515  * clutter_actor_set_margin_left:
16516  * @self: a #ClutterActor
16517  * @margin: the left margin
16518  *
16519  * Sets the margin from the left of a #ClutterActor.
16520  *
16521  * Since: 1.10
16522  */
16523 void
16524 clutter_actor_set_margin_left (ClutterActor *self,
16525                                gfloat        margin)
16526 {
16527   ClutterLayoutInfo *info;
16528
16529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16530   g_return_if_fail (margin >= 0.f);
16531
16532   info = _clutter_actor_get_layout_info (self);
16533
16534   if (info->margin.left == margin)
16535     return;
16536
16537   info->margin.left = margin;
16538
16539   clutter_actor_queue_relayout (self);
16540
16541   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16542 }
16543
16544 /**
16545  * clutter_actor_get_margin_left:
16546  * @self: a #ClutterActor
16547  *
16548  * Retrieves the left margin of a #ClutterActor.
16549  *
16550  * Return value: the left margin
16551  *
16552  * Since: 1.10
16553  */
16554 gfloat
16555 clutter_actor_get_margin_left (ClutterActor *self)
16556 {
16557   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16558
16559   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16560 }
16561
16562 /**
16563  * clutter_actor_set_margin_right:
16564  * @self: a #ClutterActor
16565  * @margin: the right margin
16566  *
16567  * Sets the margin from the right of a #ClutterActor.
16568  *
16569  * Since: 1.10
16570  */
16571 void
16572 clutter_actor_set_margin_right (ClutterActor *self,
16573                                 gfloat        margin)
16574 {
16575   ClutterLayoutInfo *info;
16576
16577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16578   g_return_if_fail (margin >= 0.f);
16579
16580   info = _clutter_actor_get_layout_info (self);
16581
16582   if (info->margin.right == margin)
16583     return;
16584
16585   info->margin.right = margin;
16586
16587   clutter_actor_queue_relayout (self);
16588
16589   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16590 }
16591
16592 /**
16593  * clutter_actor_get_margin_right:
16594  * @self: a #ClutterActor
16595  *
16596  * Retrieves the right margin of a #ClutterActor.
16597  *
16598  * Return value: the right margin
16599  *
16600  * Since: 1.10
16601  */
16602 gfloat
16603 clutter_actor_get_margin_right (ClutterActor *self)
16604 {
16605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16606
16607   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16608 }
16609
16610 static inline void
16611 clutter_actor_set_background_color_internal (ClutterActor *self,
16612                                              const ClutterColor *color)
16613 {
16614   ClutterActorPrivate *priv = self->priv;
16615   GObject *obj;
16616
16617   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16618     return;
16619
16620   obj = G_OBJECT (self);
16621
16622   priv->bg_color = *color;
16623   priv->bg_color_set = TRUE;
16624
16625   clutter_actor_queue_redraw (self);
16626
16627   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16628   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16629 }
16630
16631 /**
16632  * clutter_actor_set_background_color:
16633  * @self: a #ClutterActor
16634  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16635  *  set color
16636  *
16637  * Sets the background color of a #ClutterActor.
16638  *
16639  * The background color will be used to cover the whole allocation of the
16640  * actor. The default background color of an actor is transparent.
16641  *
16642  * To check whether an actor has a background color, you can use the
16643  * #ClutterActor:background-color-set actor property.
16644  *
16645  * The #ClutterActor:background-color property is animatable.
16646  *
16647  * Since: 1.10
16648  */
16649 void
16650 clutter_actor_set_background_color (ClutterActor       *self,
16651                                     const ClutterColor *color)
16652 {
16653   ClutterActorPrivate *priv;
16654   GObject *obj;
16655   GParamSpec *bg_color_pspec;
16656
16657   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16658
16659   obj = G_OBJECT (self);
16660
16661   priv = self->priv;
16662
16663   if (color == NULL)
16664     {
16665       priv->bg_color_set = FALSE;
16666       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16667       clutter_actor_queue_redraw (self);
16668       return;
16669     }
16670
16671   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16672   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16673     {
16674       _clutter_actor_create_transition (self, bg_color_pspec,
16675                                         &priv->bg_color,
16676                                         color);
16677     }
16678   else
16679     _clutter_actor_update_transition (self, bg_color_pspec, color);
16680
16681   clutter_actor_queue_redraw (self);
16682 }
16683
16684 /**
16685  * clutter_actor_get_background_color:
16686  * @self: a #ClutterActor
16687  * @color: (out caller-allocates): return location for a #ClutterColor
16688  *
16689  * Retrieves the color set using clutter_actor_set_background_color().
16690  *
16691  * Since: 1.10
16692  */
16693 void
16694 clutter_actor_get_background_color (ClutterActor *self,
16695                                     ClutterColor *color)
16696 {
16697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16698   g_return_if_fail (color != NULL);
16699
16700   *color = self->priv->bg_color;
16701 }
16702
16703 /**
16704  * clutter_actor_get_previous_sibling:
16705  * @self: a #ClutterActor
16706  *
16707  * Retrieves the sibling of @self that comes before it in the list
16708  * of children of @self's parent.
16709  *
16710  * The returned pointer is only valid until the scene graph changes; it
16711  * is not safe to modify the list of children of @self while iterating
16712  * it.
16713  *
16714  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16715  *
16716  * Since: 1.10
16717  */
16718 ClutterActor *
16719 clutter_actor_get_previous_sibling (ClutterActor *self)
16720 {
16721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16722
16723   return self->priv->prev_sibling;
16724 }
16725
16726 /**
16727  * clutter_actor_get_next_sibling:
16728  * @self: a #ClutterActor
16729  *
16730  * Retrieves the sibling of @self that comes after it in the list
16731  * of children of @self's parent.
16732  *
16733  * The returned pointer is only valid until the scene graph changes; it
16734  * is not safe to modify the list of children of @self while iterating
16735  * it.
16736  *
16737  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16738  *
16739  * Since: 1.10
16740  */
16741 ClutterActor *
16742 clutter_actor_get_next_sibling (ClutterActor *self)
16743 {
16744   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16745
16746   return self->priv->next_sibling;
16747 }
16748
16749 /**
16750  * clutter_actor_get_first_child:
16751  * @self: a #ClutterActor
16752  *
16753  * Retrieves the first child of @self.
16754  *
16755  * The returned pointer is only valid until the scene graph changes; it
16756  * is not safe to modify the list of children of @self while iterating
16757  * it.
16758  *
16759  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16760  *
16761  * Since: 1.10
16762  */
16763 ClutterActor *
16764 clutter_actor_get_first_child (ClutterActor *self)
16765 {
16766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16767
16768   return self->priv->first_child;
16769 }
16770
16771 /**
16772  * clutter_actor_get_last_child:
16773  * @self: a #ClutterActor
16774  *
16775  * Retrieves the last child of @self.
16776  *
16777  * The returned pointer is only valid until the scene graph changes; it
16778  * is not safe to modify the list of children of @self while iterating
16779  * it.
16780  *
16781  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16782  *
16783  * Since: 1.10
16784  */
16785 ClutterActor *
16786 clutter_actor_get_last_child (ClutterActor *self)
16787 {
16788   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16789
16790   return self->priv->last_child;
16791 }
16792
16793 /* easy way to have properly named fields instead of the dummy ones
16794  * we use in the public structure
16795  */
16796 typedef struct _RealActorIter
16797 {
16798   ClutterActor *root;           /* dummy1 */
16799   ClutterActor *current;        /* dummy2 */
16800   gpointer padding_1;           /* dummy3 */
16801   gint age;                     /* dummy4 */
16802   gpointer padding_2;           /* dummy5 */
16803 } RealActorIter;
16804
16805 /**
16806  * clutter_actor_iter_init:
16807  * @iter: a #ClutterActorIter
16808  * @root: a #ClutterActor
16809  *
16810  * Initializes a #ClutterActorIter, which can then be used to iterate
16811  * efficiently over a section of the scene graph, and associates it
16812  * with @root.
16813  *
16814  * Modifying the scene graph section that contains @root will invalidate
16815  * the iterator.
16816  *
16817  * |[
16818  *   ClutterActorIter iter;
16819  *   ClutterActor *child;
16820  *
16821  *   clutter_actor_iter_init (&iter, container);
16822  *   while (clutter_actor_iter_next (&iter, &child))
16823  *     {
16824  *       /&ast; do something with child &ast;/
16825  *     }
16826  * ]|
16827  *
16828  * Since: 1.10
16829  */
16830 void
16831 clutter_actor_iter_init (ClutterActorIter *iter,
16832                          ClutterActor     *root)
16833 {
16834   RealActorIter *ri = (RealActorIter *) iter;
16835
16836   g_return_if_fail (iter != NULL);
16837   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16838
16839   ri->root = root;
16840   ri->current = NULL;
16841   ri->age = root->priv->age;
16842 }
16843
16844 /**
16845  * clutter_actor_iter_next:
16846  * @iter: a #ClutterActorIter
16847  * @child: (out): return location for a #ClutterActor
16848  *
16849  * Advances the @iter and retrieves the next child of the root #ClutterActor
16850  * that was used to initialize the #ClutterActorIterator.
16851  *
16852  * If the iterator can advance, this function returns %TRUE and sets the
16853  * @child argument.
16854  *
16855  * If the iterator cannot advance, this function returns %FALSE, and
16856  * the contents of @child are undefined.
16857  *
16858  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16859  *
16860  * Since: 1.10
16861  */
16862 gboolean
16863 clutter_actor_iter_next (ClutterActorIter  *iter,
16864                          ClutterActor     **child)
16865 {
16866   RealActorIter *ri = (RealActorIter *) iter;
16867
16868   g_return_val_if_fail (iter != NULL, FALSE);
16869   g_return_val_if_fail (ri->root != NULL, FALSE);
16870 #ifndef G_DISABLE_ASSERT
16871   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16872 #endif
16873
16874   if (ri->current == NULL)
16875     ri->current = ri->root->priv->first_child;
16876   else
16877     ri->current = ri->current->priv->next_sibling;
16878
16879   if (child != NULL)
16880     *child = ri->current;
16881
16882   return ri->current != NULL;
16883 }
16884
16885 /**
16886  * clutter_actor_iter_prev:
16887  * @iter: a #ClutterActorIter
16888  * @child: (out): return location for a #ClutterActor
16889  *
16890  * Advances the @iter and retrieves the previous child of the root
16891  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16892  *
16893  * If the iterator can advance, this function returns %TRUE and sets the
16894  * @child argument.
16895  *
16896  * If the iterator cannot advance, this function returns %FALSE, and
16897  * the contents of @child are undefined.
16898  *
16899  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16900  *
16901  * Since: 1.10
16902  */
16903 gboolean
16904 clutter_actor_iter_prev (ClutterActorIter  *iter,
16905                          ClutterActor     **child)
16906 {
16907   RealActorIter *ri = (RealActorIter *) iter;
16908
16909   g_return_val_if_fail (iter != NULL, FALSE);
16910   g_return_val_if_fail (ri->root != NULL, FALSE);
16911 #ifndef G_DISABLE_ASSERT
16912   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16913 #endif
16914
16915   if (ri->current == NULL)
16916     ri->current = ri->root->priv->last_child;
16917   else
16918     ri->current = ri->current->priv->prev_sibling;
16919
16920   if (child != NULL)
16921     *child = ri->current;
16922
16923   return ri->current != NULL;
16924 }
16925
16926 /**
16927  * clutter_actor_iter_remove:
16928  * @iter: a #ClutterActorIter
16929  *
16930  * Safely removes the #ClutterActor currently pointer to by the iterator
16931  * from its parent.
16932  *
16933  * This function can only be called after clutter_actor_iter_next() or
16934  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16935  * than once for the same actor.
16936  *
16937  * This function will call clutter_actor_remove_child() internally.
16938  *
16939  * Since: 1.10
16940  */
16941 void
16942 clutter_actor_iter_remove (ClutterActorIter *iter)
16943 {
16944   RealActorIter *ri = (RealActorIter *) iter;
16945   ClutterActor *cur;
16946
16947   g_return_if_fail (iter != NULL);
16948   g_return_if_fail (ri->root != NULL);
16949 #ifndef G_DISABLE_ASSERT
16950   g_return_if_fail (ri->age == ri->root->priv->age);
16951 #endif
16952   g_return_if_fail (ri->current != NULL);
16953
16954   cur = ri->current;
16955
16956   if (cur != NULL)
16957     {
16958       ri->current = cur->priv->prev_sibling;
16959
16960       clutter_actor_remove_child_internal (ri->root, cur,
16961                                            REMOVE_CHILD_DEFAULT_FLAGS);
16962
16963       ri->age += 1;
16964     }
16965 }
16966
16967 /**
16968  * clutter_actor_iter_destroy:
16969  * @iter: a #ClutterActorIter
16970  *
16971  * Safely destroys the #ClutterActor currently pointer to by the iterator
16972  * from its parent.
16973  *
16974  * This function can only be called after clutter_actor_iter_next() or
16975  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16976  * than once for the same actor.
16977  *
16978  * This function will call clutter_actor_destroy() internally.
16979  *
16980  * Since: 1.10
16981  */
16982 void
16983 clutter_actor_iter_destroy (ClutterActorIter *iter)
16984 {
16985   RealActorIter *ri = (RealActorIter *) iter;
16986   ClutterActor *cur;
16987
16988   g_return_if_fail (iter != NULL);
16989   g_return_if_fail (ri->root != NULL);
16990 #ifndef G_DISABLE_ASSERT
16991   g_return_if_fail (ri->age == ri->root->priv->age);
16992 #endif
16993   g_return_if_fail (ri->current != NULL);
16994
16995   cur = ri->current;
16996
16997   if (cur != NULL)
16998     {
16999       ri->current = cur->priv->prev_sibling;
17000
17001       clutter_actor_destroy (cur);
17002
17003       ri->age += 1;
17004     }
17005 }
17006
17007 static const ClutterAnimationInfo default_animation_info = {
17008   NULL,         /* transitions */
17009   NULL,         /* states */
17010   NULL,         /* cur_state */
17011 };
17012
17013 static void
17014 clutter_animation_info_free (gpointer data)
17015 {
17016   if (data != NULL)
17017     {
17018       ClutterAnimationInfo *info = data;
17019
17020       if (info->transitions != NULL)
17021         g_hash_table_unref (info->transitions);
17022
17023       if (info->states != NULL)
17024         g_array_unref (info->states);
17025
17026       g_slice_free (ClutterAnimationInfo, info);
17027     }
17028 }
17029
17030 const ClutterAnimationInfo *
17031 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17032 {
17033   const ClutterAnimationInfo *res;
17034   GObject *obj = G_OBJECT (self);
17035
17036   res = g_object_get_qdata (obj, quark_actor_animation_info);
17037   if (res != NULL)
17038     return res;
17039
17040   return &default_animation_info;
17041 }
17042
17043 ClutterAnimationInfo *
17044 _clutter_actor_get_animation_info (ClutterActor *self)
17045 {
17046   GObject *obj = G_OBJECT (self);
17047   ClutterAnimationInfo *res;
17048
17049   res = g_object_get_qdata (obj, quark_actor_animation_info);
17050   if (res == NULL)
17051     {
17052       res = g_slice_new (ClutterAnimationInfo);
17053
17054       *res = default_animation_info;
17055
17056       g_object_set_qdata_full (obj, quark_actor_animation_info,
17057                                res,
17058                                clutter_animation_info_free);
17059     }
17060
17061   return res;
17062 }
17063
17064 ClutterTransition *
17065 _clutter_actor_get_transition (ClutterActor *actor,
17066                                GParamSpec   *pspec)
17067 {
17068   const ClutterAnimationInfo *info;
17069
17070   info = _clutter_actor_get_animation_info_or_defaults (actor);
17071
17072   if (info->transitions == NULL)
17073     return NULL;
17074
17075   return g_hash_table_lookup (info->transitions, pspec->name);
17076 }
17077
17078 typedef struct _TransitionClosure
17079 {
17080   ClutterActor *actor;
17081   ClutterTransition *transition;
17082   gchar *name;
17083   gulong completed_id;
17084 } TransitionClosure;
17085
17086 static void
17087 transition_closure_free (gpointer data)
17088 {
17089   if (G_LIKELY (data != NULL))
17090     {
17091       TransitionClosure *clos = data;
17092       ClutterTimeline *timeline;
17093
17094       timeline = CLUTTER_TIMELINE (clos->transition);
17095
17096       if (clutter_timeline_is_playing (timeline))
17097         clutter_timeline_stop (timeline);
17098
17099       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17100
17101       g_object_unref (clos->transition);
17102       g_free (clos->name);
17103
17104       g_slice_free (TransitionClosure, clos);
17105     }
17106 }
17107
17108 static void
17109 on_transition_completed (ClutterTransition *transition,
17110                          TransitionClosure *clos)
17111 {
17112   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17113   ClutterActor *actor = clos->actor;
17114   ClutterAnimationInfo *info;
17115   gint n_repeats, cur_repeat;
17116
17117   info = _clutter_actor_get_animation_info (actor);
17118
17119   /* reset the caches used by animations */
17120   clutter_actor_store_content_box (actor, NULL);
17121
17122   /* ensure that we remove the transition only at the end
17123    * of its run; we emit ::completed for every repeat
17124    */
17125   n_repeats = clutter_timeline_get_repeat_count (timeline);
17126   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17127
17128   if (cur_repeat == n_repeats)
17129     {
17130       if (clutter_transition_get_remove_on_complete (transition))
17131         {
17132           /* we take a reference here because removing the closure
17133            * will release the reference on the transition, and we
17134            * want the transition to survive the signal emission;
17135            * the master clock will release the last reference at
17136            * the end of the frame processing.
17137            */
17138           g_object_ref (transition);
17139           g_hash_table_remove (info->transitions, clos->name);
17140         }
17141     }
17142
17143   /* if it's the last transition then we clean up */
17144   if (g_hash_table_size (info->transitions) == 0)
17145     {
17146       g_hash_table_unref (info->transitions);
17147       info->transitions = NULL;
17148
17149       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17150                     _clutter_actor_get_debug_name (actor));
17151
17152       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17153     }
17154 }
17155
17156 void
17157 _clutter_actor_update_transition (ClutterActor *actor,
17158                                   GParamSpec   *pspec,
17159                                   ...)
17160 {
17161   TransitionClosure *clos;
17162   ClutterTimeline *timeline;
17163   ClutterInterval *interval;
17164   const ClutterAnimationInfo *info;
17165   va_list var_args;
17166   GType ptype;
17167   GValue initial = G_VALUE_INIT;
17168   GValue final = G_VALUE_INIT;
17169   char *error = NULL;
17170
17171   info = _clutter_actor_get_animation_info_or_defaults (actor);
17172
17173   if (info->transitions == NULL)
17174     return;
17175
17176   clos = g_hash_table_lookup (info->transitions, pspec->name);
17177   if (clos == NULL)
17178     return;
17179
17180   timeline = CLUTTER_TIMELINE (clos->transition);
17181
17182   va_start (var_args, pspec);
17183
17184   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17185
17186   g_value_init (&initial, ptype);
17187   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17188                                         pspec->name,
17189                                         &initial);
17190
17191   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17192   if (error != NULL)
17193     {
17194       g_critical ("%s: %s", G_STRLOC, error);
17195       g_free (error);
17196       goto out;
17197     }
17198
17199   interval = clutter_transition_get_interval (clos->transition);
17200   clutter_interval_set_initial_value (interval, &initial);
17201   clutter_interval_set_final_value (interval, &final);
17202
17203   /* if we're updating with an easing duration of zero milliseconds,
17204    * we just jump the timeline to the end and let it run its course
17205    */
17206   if (info->cur_state != NULL &&
17207       info->cur_state->easing_duration != 0)
17208     {
17209       guint cur_duration = clutter_timeline_get_duration (timeline);
17210       ClutterAnimationMode cur_mode =
17211         clutter_timeline_get_progress_mode (timeline);
17212
17213       if (cur_duration != info->cur_state->easing_duration)
17214         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17215
17216       if (cur_mode != info->cur_state->easing_mode)
17217         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17218
17219       clutter_timeline_rewind (timeline);
17220     }
17221   else
17222     {
17223       guint duration = clutter_timeline_get_duration (timeline);
17224
17225       clutter_timeline_advance (timeline, duration);
17226     }
17227
17228 out:
17229   g_value_unset (&initial);
17230   g_value_unset (&final);
17231
17232   va_end (var_args);
17233 }
17234
17235 /*< private >*
17236  * _clutter_actor_create_transition:
17237  * @actor: a #ClutterActor
17238  * @pspec: the property used for the transition
17239  * @...: initial and final state
17240  *
17241  * Creates a #ClutterTransition for the property represented by @pspec.
17242  *
17243  * Return value: a #ClutterTransition
17244  */
17245 ClutterTransition *
17246 _clutter_actor_create_transition (ClutterActor *actor,
17247                                   GParamSpec   *pspec,
17248                                   ...)
17249 {
17250   ClutterAnimationInfo *info;
17251   ClutterTransition *res = NULL;
17252   gboolean call_restore = FALSE;
17253   TransitionClosure *clos;
17254   va_list var_args;
17255
17256   info = _clutter_actor_get_animation_info (actor);
17257
17258   /* XXX - this will go away in 2.0
17259    *
17260    * if no state has been pushed, we assume that the easing state is
17261    * in "compatibility mode": all transitions have a duration of 0
17262    * msecs, which means that they happen immediately. in Clutter 2.0
17263    * this will turn into a g_assert(info->states != NULL), as every
17264    * actor will start with a predefined easing state
17265    */
17266   if (info->states == NULL)
17267     {
17268       clutter_actor_save_easing_state (actor);
17269       clutter_actor_set_easing_duration (actor, 0);
17270       call_restore = TRUE;
17271     }
17272
17273   if (info->transitions == NULL)
17274     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17275                                                NULL,
17276                                                transition_closure_free);
17277
17278   va_start (var_args, pspec);
17279
17280   clos = g_hash_table_lookup (info->transitions, pspec->name);
17281   if (clos == NULL)
17282     {
17283       ClutterTimeline *timeline;
17284       ClutterInterval *interval;
17285       GValue initial = G_VALUE_INIT;
17286       GValue final = G_VALUE_INIT;
17287       GType ptype;
17288       char *error;
17289
17290       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17291
17292       G_VALUE_COLLECT_INIT (&initial, ptype,
17293                             var_args, 0,
17294                             &error);
17295       if (error != NULL)
17296         {
17297           g_critical ("%s: %s", G_STRLOC, error);
17298           g_free (error);
17299           goto out;
17300         }
17301
17302       G_VALUE_COLLECT_INIT (&final, ptype,
17303                             var_args, 0,
17304                             &error);
17305
17306       if (error != NULL)
17307         {
17308           g_critical ("%s: %s", G_STRLOC, error);
17309           g_value_unset (&initial);
17310           g_free (error);
17311           goto out;
17312         }
17313
17314       /* if the current easing state has a duration of 0, then we don't
17315        * bother to create the transition, and we just set the final value
17316        * directly on the actor; we don't go through the Animatable
17317        * interface because we know we got here through an animatable
17318        * property.
17319        */
17320       if (info->cur_state->easing_duration == 0)
17321         {
17322           clutter_actor_set_animatable_property (actor,
17323                                                  pspec->param_id,
17324                                                  &final,
17325                                                  pspec);
17326           g_value_unset (&initial);
17327           g_value_unset (&final);
17328
17329           goto out;
17330         }
17331
17332       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17333
17334       g_value_unset (&initial);
17335       g_value_unset (&final);
17336
17337       res = clutter_property_transition_new (pspec->name);
17338
17339       clutter_transition_set_interval (res, interval);
17340       clutter_transition_set_remove_on_complete (res, TRUE);
17341
17342       timeline = CLUTTER_TIMELINE (res);
17343       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17344       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17345       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17346
17347       /* this will start the transition as well */
17348       clutter_actor_add_transition (actor, pspec->name, res);
17349
17350       /* the actor now owns the transition */
17351       g_object_unref (res);
17352     }
17353   else
17354     res = clos->transition;
17355
17356 out:
17357   if (call_restore)
17358     clutter_actor_restore_easing_state (actor);
17359
17360   va_end (var_args);
17361
17362   return res;
17363 }
17364
17365 /**
17366  * clutter_actor_add_transition:
17367  * @self: a #ClutterActor
17368  * @name: the name of the transition to add
17369  * @transition: the #ClutterTransition to add
17370  *
17371  * Adds a @transition to the #ClutterActor's list of animations.
17372  *
17373  * The @name string is a per-actor unique identifier of the @transition: only
17374  * one #ClutterTransition can be associated to the specified @name.
17375  *
17376  * The @transition will be started once added.
17377  *
17378  * This function will take a reference on the @transition.
17379  *
17380  * This function is usually called implicitly when modifying an animatable
17381  * property.
17382  *
17383  * Since: 1.10
17384  */
17385 void
17386 clutter_actor_add_transition (ClutterActor      *self,
17387                               const char        *name,
17388                               ClutterTransition *transition)
17389 {
17390   ClutterTimeline *timeline;
17391   TransitionClosure *clos;
17392   ClutterAnimationInfo *info;
17393
17394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17395   g_return_if_fail (name != NULL);
17396   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17397
17398   info = _clutter_actor_get_animation_info (self);
17399
17400   if (info->transitions == NULL)
17401     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17402                                                NULL,
17403                                                transition_closure_free);
17404
17405   if (g_hash_table_lookup (info->transitions, name) != NULL)
17406     {
17407       g_warning ("A transition with name '%s' already exists for "
17408                  "the actor '%s'",
17409                  name,
17410                  _clutter_actor_get_debug_name (self));
17411       return;
17412     }
17413
17414   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17415
17416   timeline = CLUTTER_TIMELINE (transition);
17417
17418   clos = g_slice_new (TransitionClosure);
17419   clos->actor = self;
17420   clos->transition = g_object_ref (transition);
17421   clos->name = g_strdup (name);
17422   clos->completed_id = g_signal_connect (timeline, "completed",
17423                                          G_CALLBACK (on_transition_completed),
17424                                          clos);
17425
17426   CLUTTER_NOTE (ANIMATION,
17427                 "Adding transition '%s' [%p] to actor '%s'",
17428                 clos->name,
17429                 clos->transition,
17430                 _clutter_actor_get_debug_name (self));
17431
17432   g_hash_table_insert (info->transitions, clos->name, clos);
17433   clutter_timeline_start (timeline);
17434 }
17435
17436 /**
17437  * clutter_actor_remove_transition:
17438  * @self: a #ClutterActor
17439  * @name: the name of the transition to remove
17440  *
17441  * Removes the transition stored inside a #ClutterActor using @name
17442  * identifier.
17443  *
17444  * If the transition is currently in progress, it will be stopped.
17445  *
17446  * This function releases the reference acquired when the transition
17447  * was added to the #ClutterActor.
17448  *
17449  * Since: 1.10
17450  */
17451 void
17452 clutter_actor_remove_transition (ClutterActor *self,
17453                                  const char   *name)
17454 {
17455   const ClutterAnimationInfo *info;
17456
17457   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17458   g_return_if_fail (name != NULL);
17459
17460   info = _clutter_actor_get_animation_info_or_defaults (self);
17461
17462   if (info->transitions == NULL)
17463     return;
17464
17465   g_hash_table_remove (info->transitions, name);
17466 }
17467
17468 /**
17469  * clutter_actor_remove_all_transitions:
17470  * @self: a #ClutterActor
17471  *
17472  * Removes all transitions associated to @self.
17473  *
17474  * Since: 1.10
17475  */
17476 void
17477 clutter_actor_remove_all_transitions (ClutterActor *self)
17478 {
17479   const ClutterAnimationInfo *info;
17480
17481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17482
17483   info = _clutter_actor_get_animation_info_or_defaults (self);
17484   if (info->transitions == NULL)
17485     return;
17486
17487   g_hash_table_remove_all (info->transitions);
17488 }
17489
17490 /**
17491  * clutter_actor_set_easing_duration:
17492  * @self: a #ClutterActor
17493  * @msecs: the duration of the easing, or %NULL
17494  *
17495  * Sets the duration of the tweening for animatable properties
17496  * of @self for the current easing state.
17497  *
17498  * Since: 1.10
17499  */
17500 void
17501 clutter_actor_set_easing_duration (ClutterActor *self,
17502                                    guint         msecs)
17503 {
17504   ClutterAnimationInfo *info;
17505
17506   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17507
17508   info = _clutter_actor_get_animation_info (self);
17509
17510   if (info->cur_state == NULL)
17511     {
17512       g_warning ("You must call clutter_actor_save_easing_state() prior "
17513                  "to calling clutter_actor_set_easing_duration().");
17514       return;
17515     }
17516
17517   if (info->cur_state->easing_duration != msecs)
17518     info->cur_state->easing_duration = msecs;
17519 }
17520
17521 /**
17522  * clutter_actor_get_easing_duration:
17523  * @self: a #ClutterActor
17524  *
17525  * Retrieves the duration of the tweening for animatable
17526  * properties of @self for the current easing state.
17527  *
17528  * Return value: the duration of the tweening, in milliseconds
17529  *
17530  * Since: 1.10
17531  */
17532 guint
17533 clutter_actor_get_easing_duration (ClutterActor *self)
17534 {
17535   const ClutterAnimationInfo *info;
17536
17537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17538
17539   info = _clutter_actor_get_animation_info_or_defaults (self);
17540
17541   if (info->cur_state != NULL)
17542     return info->cur_state->easing_duration;
17543
17544   return 0;
17545 }
17546
17547 /**
17548  * clutter_actor_set_easing_mode:
17549  * @self: a #ClutterActor
17550  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17551  *
17552  * Sets the easing mode for the tweening of animatable properties
17553  * of @self.
17554  *
17555  * Since: 1.10
17556  */
17557 void
17558 clutter_actor_set_easing_mode (ClutterActor         *self,
17559                                ClutterAnimationMode  mode)
17560 {
17561   ClutterAnimationInfo *info;
17562
17563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17564   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17565   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17566
17567   info = _clutter_actor_get_animation_info (self);
17568
17569   if (info->cur_state == NULL)
17570     {
17571       g_warning ("You must call clutter_actor_save_easing_state() prior "
17572                  "to calling clutter_actor_set_easing_mode().");
17573       return;
17574     }
17575
17576   if (info->cur_state->easing_mode != mode)
17577     info->cur_state->easing_mode = mode;
17578 }
17579
17580 /**
17581  * clutter_actor_get_easing_mode:
17582  * @self: a #ClutterActor
17583  *
17584  * Retrieves the easing mode for the tweening of animatable properties
17585  * of @self for the current easing state.
17586  *
17587  * Return value: an easing mode
17588  *
17589  * Since: 1.10
17590  */
17591 ClutterAnimationMode
17592 clutter_actor_get_easing_mode (ClutterActor *self)
17593 {
17594   const ClutterAnimationInfo *info;
17595
17596   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17597
17598   info = _clutter_actor_get_animation_info_or_defaults (self);
17599
17600   if (info->cur_state != NULL)
17601     return info->cur_state->easing_mode;
17602
17603   return CLUTTER_EASE_OUT_CUBIC;
17604 }
17605
17606 /**
17607  * clutter_actor_set_easing_delay:
17608  * @self: a #ClutterActor
17609  * @msecs: the delay before the start of the tweening, in milliseconds
17610  *
17611  * Sets the delay that should be applied before tweening animatable
17612  * properties.
17613  *
17614  * Since: 1.10
17615  */
17616 void
17617 clutter_actor_set_easing_delay (ClutterActor *self,
17618                                 guint         msecs)
17619 {
17620   ClutterAnimationInfo *info;
17621
17622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17623
17624   info = _clutter_actor_get_animation_info (self);
17625
17626   if (info->cur_state == NULL)
17627     {
17628       g_warning ("You must call clutter_actor_save_easing_state() prior "
17629                  "to calling clutter_actor_set_easing_delay().");
17630       return;
17631     }
17632
17633   if (info->cur_state->easing_delay != msecs)
17634     info->cur_state->easing_delay = msecs;
17635 }
17636
17637 /**
17638  * clutter_actor_get_easing_delay:
17639  * @self: a #ClutterActor
17640  *
17641  * Retrieves the delay that should be applied when tweening animatable
17642  * properties.
17643  *
17644  * Return value: a delay, in milliseconds
17645  *
17646  * Since: 1.10
17647  */
17648 guint
17649 clutter_actor_get_easing_delay (ClutterActor *self)
17650 {
17651   const ClutterAnimationInfo *info;
17652
17653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17654
17655   info = _clutter_actor_get_animation_info_or_defaults (self);
17656
17657   if (info->cur_state != NULL)
17658     return info->cur_state->easing_delay;
17659
17660   return 0;
17661 }
17662
17663 /**
17664  * clutter_actor_get_transition:
17665  * @self: a #ClutterActor
17666  * @name: the name of the transition
17667  *
17668  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17669  * transition @name.
17670  *
17671  * Transitions created for animatable properties use the name of the
17672  * property itself, for instance the code below:
17673  *
17674  * |[
17675  *   clutter_actor_set_easing_duration (actor, 1000);
17676  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17677  *
17678  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17679  *   g_signal_connect (transition, "completed",
17680  *                     G_CALLBACK (on_transition_complete),
17681  *                     actor);
17682  * ]|
17683  *
17684  * will call the <function>on_transition_complete</function> callback when
17685  * the transition is complete.
17686  *
17687  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17688  *   was found to match the passed name; the returned instance is owned
17689  *   by Clutter and it should not be freed
17690  *
17691  * Since: 1.10
17692  */
17693 ClutterTransition *
17694 clutter_actor_get_transition (ClutterActor *self,
17695                               const char   *name)
17696 {
17697   TransitionClosure *clos;
17698   const ClutterAnimationInfo *info;
17699
17700   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17701   g_return_val_if_fail (name != NULL, NULL);
17702
17703   info = _clutter_actor_get_animation_info_or_defaults (self);
17704   if (info->transitions == NULL)
17705     return NULL;
17706
17707   clos = g_hash_table_lookup (info->transitions, name);
17708   if (clos == NULL)
17709     return NULL;
17710
17711   return clos->transition;
17712 }
17713
17714 /**
17715  * clutter_actor_save_easing_state:
17716  * @self: a #ClutterActor
17717  *
17718  * Saves the current easing state for animatable properties, and creates
17719  * a new state with the default values for easing mode and duration.
17720  *
17721  * Since: 1.10
17722  */
17723 void
17724 clutter_actor_save_easing_state (ClutterActor *self)
17725 {
17726   ClutterAnimationInfo *info;
17727   AState new_state;
17728
17729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17730
17731   info = _clutter_actor_get_animation_info (self);
17732
17733   if (info->states == NULL)
17734     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17735
17736   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17737   new_state.easing_duration = 250;
17738   new_state.easing_delay = 0;
17739
17740   g_array_append_val (info->states, new_state);
17741
17742   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17743 }
17744
17745 /**
17746  * clutter_actor_restore_easing_state:
17747  * @self: a #ClutterActor
17748  *
17749  * Restores the easing state as it was prior to a call to
17750  * clutter_actor_save_easing_state().
17751  *
17752  * Since: 1.10
17753  */
17754 void
17755 clutter_actor_restore_easing_state (ClutterActor *self)
17756 {
17757   ClutterAnimationInfo *info;
17758
17759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17760
17761   info = _clutter_actor_get_animation_info (self);
17762
17763   if (info->states == NULL)
17764     {
17765       g_critical ("The function clutter_actor_restore_easing_state() has "
17766                   "called without a previous call to "
17767                   "clutter_actor_save_easing_state().");
17768       return;
17769     }
17770
17771   g_array_remove_index (info->states, info->states->len - 1);
17772
17773   if (info->states->len > 0)
17774     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17775   else
17776     {
17777       g_array_unref (info->states);
17778       info->states = NULL;
17779       info->cur_state = NULL;
17780     }
17781 }
17782
17783 /**
17784  * clutter_actor_set_content:
17785  * @self: a #ClutterActor
17786  * @content: (allow-none): a #ClutterContent, or %NULL
17787  *
17788  * Sets the contents of a #ClutterActor.
17789  *
17790  * Since: 1.10
17791  */
17792 void
17793 clutter_actor_set_content (ClutterActor   *self,
17794                            ClutterContent *content)
17795 {
17796   ClutterActorPrivate *priv;
17797
17798   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17799   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17800
17801   priv = self->priv;
17802
17803   if (priv->content != NULL)
17804     {
17805       _clutter_content_detached (priv->content, self);
17806       g_clear_object (&priv->content);
17807     }
17808
17809   priv->content = content;
17810
17811   if (priv->content != NULL)
17812     {
17813       g_object_ref (priv->content);
17814       _clutter_content_attached (priv->content, self);
17815     }
17816
17817   /* given that the content is always painted within the allocation,
17818    * we only need to queue a redraw here
17819    */
17820   clutter_actor_queue_redraw (self);
17821
17822   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17823
17824   /* if the content gravity is not resize-fill, and the new content has a
17825    * different preferred size than the previous one, then the content box
17826    * may have been changed. since we compute that lazily, we just notify
17827    * here, and let whomever watches :content-box do whatever they need to
17828    * do.
17829    */
17830   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17831     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17832 }
17833
17834 /**
17835  * clutter_actor_get_content:
17836  * @self: a #ClutterActor
17837  *
17838  * Retrieves the contents of @self.
17839  *
17840  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17841  *   or %NULL if none was set
17842  *
17843  * Since: 1.10
17844  */
17845 ClutterContent *
17846 clutter_actor_get_content (ClutterActor *self)
17847 {
17848   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17849
17850   return self->priv->content;
17851 }
17852
17853 /**
17854  * clutter_actor_set_content_gravity:
17855  * @self: a #ClutterActor
17856  * @gravity: the #ClutterContentGravity
17857  *
17858  * Sets the gravity of the #ClutterContent used by @self.
17859  *
17860  * See the description of the #ClutterActor:content-gravity property for
17861  * more information.
17862  *
17863  * The #ClutterActor:content-gravity property is animatable.
17864  *
17865  * Since: 1.10
17866  */
17867 void
17868 clutter_actor_set_content_gravity (ClutterActor *self,
17869                                    ClutterContentGravity  gravity)
17870 {
17871   ClutterActorPrivate *priv;
17872
17873   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17874
17875   priv = self->priv;
17876
17877   if (priv->content_gravity == gravity)
17878     return;
17879
17880   priv->content_box_valid = FALSE;
17881
17882   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17883     {
17884       ClutterActorBox from_box, to_box;
17885
17886       clutter_actor_get_content_box (self, &from_box);
17887
17888       priv->content_gravity = gravity;
17889
17890       clutter_actor_get_content_box (self, &to_box);
17891
17892       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17893                                         &from_box,
17894                                         &to_box);
17895     }
17896   else
17897     {
17898       ClutterActorBox to_box;
17899
17900       priv->content_gravity = gravity;
17901
17902       clutter_actor_get_content_box (self, &to_box);
17903
17904       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17905                                         &to_box);
17906     }
17907
17908   clutter_actor_queue_redraw (self);
17909
17910   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17911 }
17912
17913 /**
17914  * clutter_actor_get_content_gravity:
17915  * @self: a #ClutterActor
17916  *
17917  * Retrieves the content gravity as set using
17918  * clutter_actor_get_content_gravity().
17919  *
17920  * Return value: the content gravity
17921  *
17922  * Since: 1.10
17923  */
17924 ClutterContentGravity
17925 clutter_actor_get_content_gravity (ClutterActor *self)
17926 {
17927   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17928                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17929
17930   return self->priv->content_gravity;
17931 }
17932
17933 /**
17934  * clutter_actor_get_content_box:
17935  * @self: a #ClutterActor
17936  * @box: (out caller-allocates): the return location for the bounding
17937  *   box for the #ClutterContent
17938  *
17939  * Retrieves the bounding box for the #ClutterContent of @self.
17940  *
17941  * The bounding box is relative to the actor's allocation.
17942  *
17943  * If no #ClutterContent is set for @self, or if @self has not been
17944  * allocated yet, then the result is undefined.
17945  *
17946  * The content box is guaranteed to be, at most, as big as the allocation
17947  * of the #ClutterActor.
17948  *
17949  * If the #ClutterContent used by the actor has a preferred size, then
17950  * it is possible to modify the content box by using the
17951  * #ClutterActor:content-gravity property.
17952  *
17953  * Since: 1.10
17954  */
17955 void
17956 clutter_actor_get_content_box (ClutterActor    *self,
17957                                ClutterActorBox *box)
17958 {
17959   ClutterActorPrivate *priv;
17960   gfloat content_w, content_h;
17961   gfloat alloc_w, alloc_h;
17962
17963   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17964   g_return_if_fail (box != NULL);
17965
17966   priv = self->priv;
17967
17968   box->x1 = 0.f;
17969   box->y1 = 0.f;
17970   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17971   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17972
17973   if (priv->content_box_valid)
17974     {
17975       *box = priv->content_box;
17976       return;
17977     }
17978
17979   /* no need to do any more work */
17980   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17981     return;
17982
17983   if (priv->content == NULL)
17984     return;
17985
17986   /* if the content does not have a preferred size then there is
17987    * no point in computing the content box
17988    */
17989   if (!clutter_content_get_preferred_size (priv->content,
17990                                            &content_w,
17991                                            &content_h))
17992     return;
17993
17994   alloc_w = box->x2;
17995   alloc_h = box->y2;
17996
17997   switch (priv->content_gravity)
17998     {
17999     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18000       box->x2 = box->x1 + MIN (content_w, alloc_w);
18001       box->y2 = box->y1 + MIN (content_h, alloc_h);
18002       break;
18003
18004     case CLUTTER_CONTENT_GRAVITY_TOP:
18005       if (alloc_w > content_w)
18006         {
18007           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18008           box->x2 = box->x1 + content_w;
18009         }
18010       box->y2 = box->y1 + MIN (content_h, alloc_h);
18011       break;
18012
18013     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18014       if (alloc_w > content_w)
18015         {
18016           box->x1 += (alloc_w - content_w);
18017           box->x2 = box->x1 + content_w;
18018         }
18019       box->y2 = box->y1 + MIN (content_h, alloc_h);
18020       break;
18021
18022     case CLUTTER_CONTENT_GRAVITY_LEFT:
18023       box->x2 = box->x1 + MIN (content_w, alloc_w);
18024       if (alloc_h > content_h)
18025         {
18026           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18027           box->y2 = box->y1 + content_h;
18028         }
18029       break;
18030
18031     case CLUTTER_CONTENT_GRAVITY_CENTER:
18032       if (alloc_w > content_w)
18033         {
18034           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18035           box->x2 = box->x1 + content_w;
18036         }
18037       if (alloc_h > content_h)
18038         {
18039           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18040           box->y2 = box->y1 + content_h;
18041         }
18042       break;
18043
18044     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18045       if (alloc_w > content_w)
18046         {
18047           box->x1 += (alloc_w - content_w);
18048           box->x2 = box->x1 + content_w;
18049         }
18050       if (alloc_h > content_h)
18051         {
18052           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18053           box->y2 = box->y1 + content_h;
18054         }
18055       break;
18056
18057     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18058       box->x2 = box->x1 + MIN (content_w, alloc_w);
18059       if (alloc_h > content_h)
18060         {
18061           box->y1 += (alloc_h - content_h);
18062           box->y2 = box->y1 + content_h;
18063         }
18064       break;
18065
18066     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18067       if (alloc_w > content_w)
18068         {
18069           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18070           box->x2 = box->x1 + content_w;
18071         }
18072       if (alloc_h > content_h)
18073         {
18074           box->y1 += (alloc_h - content_h);
18075           box->y2 = box->y1 + content_h;
18076         }
18077       break;
18078
18079     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18080       if (alloc_w > content_w)
18081         {
18082           box->x1 += (alloc_w - content_w);
18083           box->x2 = box->x1 + content_w;
18084         }
18085       if (alloc_h > content_h)
18086         {
18087           box->y1 += (alloc_h - content_h);
18088           box->y2 = box->y1 + content_h;
18089         }
18090       break;
18091
18092     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18093       g_assert_not_reached ();
18094       break;
18095
18096     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18097       {
18098         double r_c = content_w / content_h;
18099         double r_a = alloc_w / alloc_h;
18100
18101         if (r_c >= 1.0)
18102           {
18103             if (r_a >= 1.0)
18104               {
18105                 box->x1 = 0.f;
18106                 box->x2 = alloc_w;
18107
18108                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18109                 box->y2 = box->y1 + (alloc_w * r_c);
18110               }
18111             else
18112               {
18113                 box->y1 = 0.f;
18114                 box->y2 = alloc_h;
18115
18116                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18117                 box->x2 = box->x1 + (alloc_h * r_c);
18118               }
18119           }
18120         else
18121           {
18122             if (r_a >= 1.0)
18123               {
18124                 box->y1 = 0.f;
18125                 box->y2 = alloc_h;
18126
18127                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18128                 box->x2 = box->x1 + (alloc_h * r_c);
18129               }
18130             else
18131               {
18132                 box->x1 = 0.f;
18133                 box->x2 = alloc_w;
18134
18135                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18136                 box->y2 = box->y1 + (alloc_w * r_c);
18137               }
18138           }
18139       }
18140       break;
18141     }
18142 }
18143
18144 /**
18145  * clutter_actor_set_content_scaling_filters:
18146  * @self: a #ClutterActor
18147  * @min_filter: the minification filter for the content
18148  * @mag_filter: the magnification filter for the content
18149  *
18150  * Sets the minification and magnification filter to be applied when
18151  * scaling the #ClutterActor:content of a #ClutterActor.
18152  *
18153  * The #ClutterActor:minification-filter will be used when reducing
18154  * the size of the content; the #ClutterActor:magnification-filter
18155  * will be used when increasing the size of the content.
18156  *
18157  * Since: 1.10
18158  */
18159 void
18160 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18161                                            ClutterScalingFilter  min_filter,
18162                                            ClutterScalingFilter  mag_filter)
18163 {
18164   ClutterActorPrivate *priv;
18165   gboolean changed;
18166   GObject *obj;
18167
18168   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18169
18170   priv = self->priv;
18171   obj = G_OBJECT (self);
18172
18173   g_object_freeze_notify (obj);
18174
18175   changed = FALSE;
18176
18177   if (priv->min_filter != min_filter)
18178     {
18179       priv->min_filter = min_filter;
18180       changed = TRUE;
18181
18182       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18183     }
18184
18185   if (priv->mag_filter != mag_filter)
18186     {
18187       priv->mag_filter = mag_filter;
18188       changed = TRUE;
18189
18190       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18191     }
18192
18193   if (changed)
18194     clutter_actor_queue_redraw (self);
18195
18196   g_object_thaw_notify (obj);
18197 }
18198
18199 /**
18200  * clutter_actor_get_content_scaling_filters:
18201  * @self: a #ClutterActor
18202  * @min_filter: (out) (allow-none): return location for the minification
18203  *   filter, or %NULL
18204  * @mag_filter: (out) (allow-none): return location for the magnification
18205  *   filter, or %NULL
18206  *
18207  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18208  *
18209  * Since: 1.10
18210  */
18211 void
18212 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18213                                            ClutterScalingFilter *min_filter,
18214                                            ClutterScalingFilter *mag_filter)
18215 {
18216   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18217
18218   if (min_filter != NULL)
18219     *min_filter = self->priv->min_filter;
18220
18221   if (mag_filter != NULL)
18222     *mag_filter = self->priv->mag_filter;
18223 }
18224
18225 /*
18226  * clutter_actor_queue_compute_expand:
18227  * @self: a #ClutterActor
18228  *
18229  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18230  * and its parents up to the top-level actor.
18231  *
18232  * This function also queues a relayout if anything changed.
18233  */
18234 static inline void
18235 clutter_actor_queue_compute_expand (ClutterActor *self)
18236 {
18237   ClutterActor *parent;
18238   gboolean changed;
18239
18240   if (self->priv->needs_compute_expand)
18241     return;
18242
18243   changed = FALSE;
18244   parent = self;
18245   while (parent != NULL)
18246     {
18247       if (!parent->priv->needs_compute_expand)
18248         {
18249           parent->priv->needs_compute_expand = TRUE;
18250           changed = TRUE;
18251         }
18252
18253       parent = parent->priv->parent;
18254     }
18255
18256   if (changed)
18257     clutter_actor_queue_relayout (self);
18258 }
18259
18260 /**
18261  * clutter_actor_set_x_expand:
18262  * @self: a #ClutterActor
18263  * @expand: whether the actor should expand horizontally
18264  *
18265  * Sets whether a #ClutterActor should expand horizontally; this means
18266  * that layout manager should allocate extra space for the actor, if
18267  * possible.
18268  *
18269  * Setting an actor to expand will also make all its parent expand, so
18270  * that it's possible to build an actor tree and only set this flag on
18271  * its leaves and not on every single actor.
18272  *
18273  * Since: 1.12
18274  */
18275 void
18276 clutter_actor_set_x_expand (ClutterActor *self,
18277                             gboolean      expand)
18278 {
18279   ClutterLayoutInfo *info;
18280
18281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18282
18283   expand = !!expand;
18284
18285   info = _clutter_actor_get_layout_info (self);
18286   if (info->x_expand != expand)
18287     {
18288       info->x_expand = expand;
18289
18290       self->priv->x_expand_set = TRUE;
18291
18292       clutter_actor_queue_compute_expand (self);
18293
18294       g_object_notify_by_pspec (G_OBJECT (self),
18295                                 obj_props[PROP_X_EXPAND]);
18296     }
18297 }
18298
18299 /**
18300  * clutter_actor_get_x_expand:
18301  * @self: a #ClutterActor
18302  *
18303  * Retrieves the value set with clutter_actor_set_x_expand().
18304  *
18305  * See also: clutter_actor_needs_x_expand()
18306  *
18307  * Return value: %TRUE if the actor has been set to expand
18308  *
18309  * Since: 1.12
18310  */
18311 gboolean
18312 clutter_actor_get_x_expand (ClutterActor *self)
18313 {
18314   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18315
18316   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18317 }
18318
18319 /**
18320  * clutter_actor_set_y_expand:
18321  * @self: a #ClutterActor
18322  * @expand: whether the actor should expand vertically
18323  *
18324  * Sets whether a #ClutterActor should expand horizontally; this means
18325  * that layout manager should allocate extra space for the actor, if
18326  * possible.
18327  *
18328  * Setting an actor to expand will also make all its parent expand, so
18329  * that it's possible to build an actor tree and only set this flag on
18330  * its leaves and not on every single actor.
18331  *
18332  * Since: 1.12
18333  */
18334 void
18335 clutter_actor_set_y_expand (ClutterActor *self,
18336                             gboolean      expand)
18337 {
18338   ClutterLayoutInfo *info;
18339
18340   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18341
18342   expand = !!expand;
18343
18344   info = _clutter_actor_get_layout_info (self);
18345   if (info->y_expand != expand)
18346     {
18347       info->y_expand = expand;
18348
18349       self->priv->y_expand_set = TRUE;
18350
18351       clutter_actor_queue_compute_expand (self);
18352
18353       g_object_notify_by_pspec (G_OBJECT (self),
18354                                 obj_props[PROP_Y_EXPAND]);
18355     }
18356 }
18357
18358 /**
18359  * clutter_actor_get_y_expand:
18360  * @self: a #ClutterActor
18361  *
18362  * Retrieves the value set with clutter_actor_set_y_expand().
18363  *
18364  * See also: clutter_actor_needs_y_expand()
18365  *
18366  * Return value: %TRUE if the actor has been set to expand
18367  *
18368  * Since: 1.12
18369  */
18370 gboolean
18371 clutter_actor_get_y_expand (ClutterActor *self)
18372 {
18373   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18374
18375   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18376 }
18377
18378 static void
18379 clutter_actor_compute_expand_recursive (ClutterActor *self,
18380                                         gboolean     *x_expand_p,
18381                                         gboolean     *y_expand_p)
18382 {
18383   ClutterActorIter iter;
18384   ClutterActor *child;
18385   gboolean x_expand, y_expand;
18386
18387   x_expand = y_expand = FALSE;
18388
18389   clutter_actor_iter_init (&iter, self);
18390   while (clutter_actor_iter_next (&iter, &child))
18391     {
18392       x_expand = x_expand || clutter_actor_needs_x_expand (child);
18393       y_expand = y_expand || clutter_actor_needs_y_expand (child);
18394     }
18395
18396   *x_expand_p = x_expand;
18397   *y_expand_p = y_expand;
18398 }
18399
18400 static void
18401 clutter_actor_compute_expand (ClutterActor *self)
18402 {
18403   if (self->priv->needs_compute_expand)
18404     {
18405       const ClutterLayoutInfo *info;
18406       gboolean x_expand, y_expand;
18407
18408       info = _clutter_actor_get_layout_info_or_defaults (self);
18409
18410       if (self->priv->x_expand_set)
18411         x_expand = info->x_expand;
18412       else
18413         x_expand = FALSE;
18414
18415       if (self->priv->y_expand_set)
18416         y_expand = info->y_expand;
18417       else
18418         y_expand = FALSE;
18419
18420       /* we don't need to recurse down to the children if the
18421        * actor has been forcibly set to expand
18422        */
18423       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18424         {
18425           if (self->priv->n_children != 0)
18426             {
18427               gboolean *x_expand_p, *y_expand_p;
18428               gboolean ignored = FALSE;
18429
18430               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18431               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18432
18433               clutter_actor_compute_expand_recursive (self,
18434                                                       x_expand_p,
18435                                                       y_expand_p);
18436             }
18437         }
18438
18439       self->priv->needs_compute_expand = FALSE;
18440       self->priv->needs_x_expand = (x_expand != FALSE);
18441       self->priv->needs_y_expand = (y_expand != FALSE);
18442     }
18443 }
18444
18445 /**
18446  * clutter_actor_needs_x_expand:
18447  * @self: a #ClutterActor
18448  *
18449  * Checks whether an actor, or any of its children, is set to expand
18450  * horizontally.
18451  *
18452  * This function should only be called by layout managers that can
18453  * assign extra space to their children.
18454  *
18455  * If you want to know whether the actor was explicitly set to expand,
18456  * use clutter_actor_get_y_expand().
18457  *
18458  * Return value: %TRUE if the actor should expand
18459  *
18460  * Since: 1.12
18461  */
18462 gboolean
18463 clutter_actor_needs_x_expand (ClutterActor *self)
18464 {
18465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18466
18467   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18468     return FALSE;
18469
18470   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18471     return FALSE;
18472
18473   clutter_actor_compute_expand (self);
18474
18475   return self->priv->needs_x_expand;
18476 }
18477
18478 /**
18479  * clutter_actor_needs_y_expand:
18480  * @self: a #ClutterActor
18481  *
18482  * Checks whether an actor, or any of its children, is set to expand
18483  * vertically.
18484  *
18485  * This function should only be called by layout managers that can
18486  * assign extra space to their children.
18487  *
18488  * If you want to know whether the actor was explicitly set to expand,
18489  * use clutter_actor_get_y_expand().
18490  *
18491  * Return value: %TRUE if the actor should expand
18492  *
18493  * Since: 1.12
18494  */
18495 gboolean
18496 clutter_actor_needs_y_expand (ClutterActor *self)
18497 {
18498   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18499
18500   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18501     return FALSE;
18502
18503   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18504     return FALSE;
18505
18506   clutter_actor_compute_expand (self);
18507
18508   return self->priv->needs_x_expand;
18509 }